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
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号
首先纠正题主理解上的错误:
对象
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,构建对象,暂且称这个对象为temptemp的原型指向挂在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
方法是从原型链中继承来的没错。然而方法体中的
this是什么,与这个方法来自哪里没有关系,而是跟方法调用方式有关。你是用o调用的,所以this就是o,就是你new出来的Sub实例。所以
this.name首先是到你的o上面去找,找不到再沿原型链向上查找。o->Sub->Super
你要是不在Sub构造函数里面加上
那就能得到 this is super.
翻看一下js 原型链的知识- -
无论
o.say()的say()方法是从哪里继承下来的其函数内部的指令肯定是
console.log(this.name);这里的这句命令,会被带回到调用者那里。
this也会指向 调用者o此时
o根据原型链最近的方法调用了say函数所以会输出
"this is sub"@linkFly