function Super(){
this.name = "this is super";
}
Super.prototype = {
say:function(){
console.log(this.name);
}
}
function Sub(){
this.name = "this is sub";
}
Sub.prototype = new Super();
var o = new Sub();
o.say(); //this is sub
实例 o 的原型对象的constructor是Super,那么 this.name 应该是Super的构造函数。但是输出是 this is sub
首先纠正题主理解上的错误:
对象
o
的constructor是Sub
而不是Super
。对象o
的指向是Sub
,然后Sub
继承自Super
,var o = new Sub()
执行的是构造函数Sub
,而Sub
中又执行了this.name = "this is sub";
。下面我们来深入分析一下题主代码的原理以及通过
prototype
继承发生的事情。别的不多说,我们来run一遍代码:这是题主的源代码:
我们来看执行,前面的一堆声明我们先不看。
第一步,原型链继承
这里发生了几件事:
把
Sub.prototype
设置为了new Supper
执行
new Super
,构建对象,暂且称这个对象为temp
temp
的原型指向挂在temp.__proto__
下,大体可理解为temp.__proto__ = Sub.prototype
设置temp的属性,即这段代码:
当这句
Sub.prototype = new Super()
执行完了之后,Sub.prototype是个什么状态呢?
,console
一下我们就知道了:或者我们可以简单的理解为这样:
其实这时候,
Sub
已经成功继承了Super
,内存指向如图。第二步,创建对象
o
:这里发生了几件事:
执行构造函数
Sub
设置
o.__proto__=Sub.prototype
,这时候对象o
大概可以理解为这样:然后执行的,就是题主困惑的地方:构造函数
Sub
中执行了代码this.name="this is sub"
,即设置了o.name="this is sub"
,执行完了这里,对象o
大体已经长成这样了:相比到了这里,大家应该知道是怎么一回事了吧,这时候内存指向如图:
所以最后,当执行
o.say();
的时候,输出的是this is sub
。-------------- update - 应题主后来的追问:
题主后来追问内容:
首先
constructor
是不安全属性,它是允许被重写的:更鲜明一点的例子,我们直接声明一个对象:
源代码中,
prototype.constructor
已经被重写为Object
,因为这几段关键代码:所以在题主的源代码上,这两段代码可以印证一切:
因为
constructor
是不安全属性,它是允许被重写的,所以题主追问的判定代码并不正确。另外
constructor
在对象的实现上是在构造函数里传递指向的,具体的实现可以参阅《ECMA-262标准实现规范 —— createdynamicfunction()》。也即是说,是先运行构造函数,后指向
constructor
的(在构造函数里指向constructor
)。本答案原创于 @linkFly ,和segmentfault.com共享,转载需保留本声明。
前端开发QQ群:377786580