如果不覆盖构造函数属性,为什么对象的构造函数属性指向父类的构造函数而不是扩展函数中的F.

时间:2014-08-21 14:47:12

标签: javascript

我辨别着名的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的属性 - 这是我得到了什么。

3 个答案:

答案 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;
}