javascript - 原型对象的constructor
问题描述
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一遍代码:
这是题主的源代码:
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
我们来看执行,前面的一堆声明我们先不看。
第一步,原型链继承
Sub.prototype=new Super();
这里发生了几件事:
把
Sub.prototype
设置为了new Supper
执行
new Super
,构建对象,暂且称这个对象为temp
temp
的原型指向挂在temp.__proto__
下,大体可理解为temp.__proto__ = Sub.prototype
-
设置temp的属性,即这段代码:
temp.name="this is super"
当这句Sub.prototype = new Super()
执行完了之后,Sub.prototype是个什么状态呢?
,console
一下我们就知道了:
{
name : "this is super",
__proto__ : {
say : function () {
console.log(this.name);
},
__proto__:...
}
}
或者我们可以简单的理解为这样:
Sub.prototype={
name : "this is super",
say : function () {
console.log(this.name);
}
};
其实这时候,Sub
已经成功继承了Super
,内存指向如图。
第二步,创建对象o
:
var o = new Sub();
这里发生了几件事:
执行构造函数
Sub
-
设置
o.__proto__=Sub.prototype
,这时候对象o
大概可以理解为这样:{ name: 'this is super', say: function () { console.log(this.name); } }
-
然后执行的,就是题主困惑的地方:构造函数
Sub
中执行了代码this.name="this is sub"
,即设置了o.name="this is sub"
,执行完了这里,对象o
大体已经长成这样了:{ name: 'this is sub', say: function () { console.log(this.name); } }
相比到了这里,大家应该知道是怎么一回事了吧,这时候内存指向如图:
所以最后,当执行o.say();
的时候,输出的是this is sub
。
-------------- update - 应题主后来的追问:
题主后来追问内容:
var o = new Sub(); // 之前 Sub.prototype已经修改了,很疑惑构造函数是Sub。
Sub.prototype.constructor === Sub //false
new Sub() 执行的构造函数 不根据Sub.prototype.constructor 的指向么?
首先constructor
是不安全属性,它是允许被重写的:
function Foo() {
this.name = 'foo';
}
Foo.prototype = {};
var foo = new Foo;//{ }
foo.constructor == Foo.prototype.constructor //true
foo instanceof Foo //true
更鲜明一点的例子,我们直接声明一个对象:
var foo = { };
foo.constructor == Object.prototype.constructor //true
源代码中,prototype.constructor
已经被重写为Object
,因为这几段关键代码:
//省略部分代码
Super.prototype = {
//这时候Super.prototype.constructor就已经指向Object了
say: function () {
console.log(this.name);
}
}
//省略部分代码
//这时候Sub.prototype.constructor也已经指向了Object
Sub.prototype = new Super();
所以在题主的源代码上,这两段代码可以印证一切:
Super.prototype.constructor === Object //true
Sub.prototype.constructor === Object //true
因为constructor
是不安全属性,它是允许被重写的,所以题主追问的判定代码并不正确。
另外constructor
在对象的实现上是在构造函数里传递指向的,具体的实现可以参阅《ECMA-262标准实现规范 —— createdynamicfunction()》。
也即是说,是先运行构造函数,后指向constructor
的(在构造函数里指向constructor
)。
本答案原创于 @linkFly ,和segmentfault.com共享,转载需保留本声明。
前端开发QQ群:377786580
这篇关于javascript - 原型对象的constructor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!