我辨别着名的JS extend
函数:
function extend(parent, child) {
var F = new Function();
F.prototype = parent.prototype;
child.prototype = new F();
//child.prototype.constructor = Child
}
我已经注释掉了构造函数属性被覆盖的行。如果我按以下方式创建对象:
var p = function p() {this.parent = true};
var c = function c() {this.child = true};
extend(p, c);
console.log((new c()).constructor); //outputs reference to `p` constructor, why?
我的问题是为什么构造函数引用var p = function p() {this.parent = true};
而不是变量F
指向的匿名函数?构造函数属性手册指出constructor property returns a reference to the Object function that created the instance's prototype
和实例原型new F()
是由匿名函数创建的。那为什么它指向另一件事呢?
更新
我根据HMR
的回答做出以下假设是否正确?
创建新函数时,JS引擎会创建新的空对象,并设置函数的prototype
属性以指向此新创建的对象。然后JS引擎向该对象添加constructor
属性,指向创建的函数。
所以现在我的情况。当var F = new Function()
JS引擎时:
1)创建新的F
功能
2)创建新对象(让它为oF
)
3)设置原型F.prototype = oF
4)设置构造函数oF.constructor = F
同样适用于function p
,其原型oP
的构造函数属性设置为function p
。我们记得,F.prototype
指向oF
,但在我们执行以下行F.prototype = parent.prototype
之后,它现在指向oP
。然后,当我们访问(new c()).constructor
属性new c()
时,对象没有它,因此JS引擎开始向后查看原型并找到oP
上指向function p
的属性 - 这是我得到了什么。
答案 0 :(得分:2)
如果在实例上找不到成员,则JS引擎将查看原型链。原型链是一堆具有__proto__
另一个对象的对象,直到它为空。
请注意__proto__
是非标准属性,用于解释原型链中首次使用的对象。
由于您将child.prototype替换为具有__proto__
parent.prototype的空对象,因此JS引擎无法在c child.prototype
上找到构造函数,但它会在{{1}上找到它这是parent.prototype。
当你这样做时:
child.prototype.__proto__
它将它添加到child.prototype,因此它不会改变child.prototype.constructor=child;
中的parent.prototype。这称为阴影。
有关原型和构造函数的更多信息here。
<强> [更新] 强>
继承后的原型链如下所示:
child.prototype.__proto__
答案 1 :(得分:0)
你应该把
F.prototype = parent;
你这样做的方式就是说&#34;两个构造函数是相同的&#34;,用我展示的例子,你会说&#34; F构造函数是相等的父构造函数&#34; < / p>
答案 2 :(得分:0)
问题是在此过程中child
构造函数实际上已丢失。
function extend(parent, child) {
// Create a completely blank anonymous function
var F = new Function();
// Give it all the same properties as the parent, including constructor
F.prototype = parent.prototype;
// Overwrite the childs prototype with an instance of the parent
child.prototype = new F();
}
由于child
原型被parent.prototype
的实例覆盖,child.prototype.constructor
也会被覆盖。
就个人而言,这里是我使用的扩展功能,它运行得很漂亮。
function extend(Derived, Base) {
Derived.prototype = Object.create(Base.prototype);
Derived.constructor = Derived;
}