You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
proto 一个对象,作为新创建对象的原型。
propertiesObject 可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProperties()的第二个参数一样)。注意:该参数对象不能是undefined,另外只有该对象中自身拥有的可枚举的属性才有效,也就是说该对象的原型链上属性是无效的。
与其它编程语言不一样的是,javascript的面向对象并非依赖于抽象的类,而是通过
原型链
,将一个个具体的对象实例进行连接,位于原型链下游的对象实例可以读取/使用位于上游的对象实例的属性/方法。下文由简及深,试图一步步理清javascript面向对象的本质。
万物之源:javascript的原生类型——
Object
javascript定义了最基础的对象类型
Object
,并且为这一对象类型定义了许多成员方法。其它许多原生对象类型,实际上都是继承自Object
,比如说Function
、Date
等。想要生成一个Object
对象类型的对象实例也不是一件什么难事:实际上,更符合面向对象思想的应该是利用构造函数来生成对象实例。
生成对象实例的运算符
new
,以及构造函数constructor
如何使用
new
这一运算符来生成对象实例在其它编程语言中,
new
往往也是用来生成对象实例的,用法一般是这样:new ClassName[([arguments])]
,而生成出来的对象实例也被冠以“ClassName对象”这样的称谓;而javascript则大不相同,由于原生没有类这一概念,因此构造函数
便取而代之:new constructor[([arguments])]
,而称谓也改为“constructor对象”或"constructor类型的对象",构造函数名直接就等同于数据类型了。从上图可知,利用构造函数A生成的实例对象obj的数据类型为A,另外,我们留意到obj有且只有一个
__proto__
属性,这是什么呢?先别急,下面就说到。详述构造函数
constructor
从上文可知,要想生成对象实例,必须使用构造函数(
constructor
),即便是var arr = [];
或var obj = {}
这样的形式,javascript也会在内部调用Function()
、Object()
这样预设的构造函数(由于是预设的构造函数/数据类型,因此不需显式指定)。继续沿用上述例子,这次我们把构造函数A打印出来看看长什么样儿:
实际上,构造函数跟普通的函数并无二致,只是因为用途(用来生成对象实例),因此才冠以“构造函数”的大名。从上图看,我们略过一些与面向对象无关的属性(arguments/caller/length/name),以及其函数作用域(
<function scope>
),剩下的就是与面向对象息息相关的俩属性了:prototype
和__proto__
。这__proto__
分外眼熟,赫然也出现在对象实例obj里,不过这里还是先跳过,我们先说这prototype
属性。构造函数中的
prototype
属性特别注明是“构造函数中的
prototype
属性”,是因为,对于一般的函数来说,prototype
属性没什么意义。prototype
属性指定了使用该构造函数生成的对象实例继承了哪个对象实例。如上述的function A()的
prototype
属性指向了一个默认的Object
类型的对象实例(在javascript中,变量只是对象实例的一个引用,因此此处用“指向”比较准确),那么,用function A()作为构造函数实例化的obj实际上就是继承了那默认的Object类型的对象实例,虽然obj本身并没有自定义的属性/方法,但是能通过obj调用继承回来的所有属性/方法。对象继承的单向链条:原型链
既然构造函数的
prototype
属性能指定继承的对象实例,那么只要我们修改这prototype
属性,使其指向其它对象实例,那么就可以达到实现继承任意对象的效果了,看下面代码:先来看看构造函数audi打印出来的结果:
从audi.prototype.status可以看出,此时的audi.prototype的确是指向
{status: 'stop'}
这个对象实例了。那么接下来看看利用修改后的构造函数audi所生成的对象实例audiQ3:
我们可以发现audiQ3这一实例对象的数据类型是
audi
(与构造函数同名),另外,audiQ3其下只有__proto__
这唯一一个成员属性,继续查看__proto__
,赫然发现,里面竟然有status: "stop"
。没错,__proto__
属性正是指向{status: 'stop'}
这个对象实例的一个引用。原型链的接点:
__proto__
通过对象实例中的
__proto__
属性,继承的对象实例得以与被继承的对象实例链接起来,于是,一环扣一环,形成了一条由对象实例、指向被继承对象实例的引用所构成的链条:原型链。由于
__proto__
是由构造函数的prototype
属性决定的(也可以说是prototype
直接赋值给__proto__
),因此我们可以通过修改prototype
属性来操纵这条原型链
。再谈构造函数
构造函数,主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,那么,javascript里的构造函数,是怎么实现这样的功能的呢?以下面的DEMO作为示例说明:
首先来看构造函数car,我们看到
this.status = 'stop';
,这this
是指代car这一function吗?不是的,这个this
实际上是指向当前函数执行时的上下文环境,用在构造函数时,指的则是新生成的对象实例(在本DEMO中指的是audiQ3)。因此,只要利用this
,就能在构造函数中,为未来利用此构造函数生成的对象实例,添加成员属性和成员方法了。javascript原生支持的原型继承方式:
Object.create
ECMAScript 5
定义了一种原生的原型继承方式:Object.create
,我们可以通过这种方式更简便地实现原型继承。语法
参数
示例
怎么样,利用
Object.create
这种方法是不是很简单就实现了原型继承呢?实际上,这是ECMAScript 5
给我们做了一下封装,相当于:浏览器兼容性修复
考虑到
ECMAScript 5
在IE上到IE10
才完全支持,因此我们有必要对低版本的IE浏览器进行兼容,实际上也很简单,对上面的代码稍作修改即可:The text was updated successfully, but these errors were encountered: