7

我正在开发一个使用原型继承的 JavaScript 项目。我决定使用它的方式如下:

var MySuperClass = function (param) {
    this.prop = param;
};
MySuperClass.prototype.myFunc = function () {
    console.log(this.prop);
};

var MySubClass = function (param) {
    MySuperClass.call(this, param);
};
MySubClass.prototype = new MySuperClass();
MySubClass.prototype.constructor = MySubClass;

var obj = new MySubClass('value');
obj.myFunc();

强调继承。

问题在于,如果我在每个类(超类和子类)的构造函数中放置一个 console.log,超类会被调用两次,一次是在MySubClass.prototype = new MySuperClass();没有任何参数的情况下传递给子类,一次是有参数当它在子类的构造函数中是“构造函数被盗”时。

如果我随后尝试保存这些参数,这可能会导致错误(这意味着我必须添加逻辑来处理空参数)。

现在,如果我这样做:

var MySubClass = function (param) {
    MySuperClass.call(this, param);
};
MySubClass.prototype = MySuperClass;
MySubClass.prototype.constructor = MySubClass;

一切似乎都正常,但我以前从未见过有人这样做(在我的谷歌搜索中)。

任何人都可以向我解释第二个是否以及如何不正确(它似乎类似于 Crockford 继承函数)以及如何修复第一个不触发两次,如果可以的话?

4

1 回答 1

8

这样做不是正确的解决方案:

MySubClass.prototype = MySuperClass;

您将函数本身设置为原型而不是原型对象,因此您不会继承您所期望的。


但你是对的。这样做会调用构造函数,这可能会导致问题。

MySubClass.prototype = new MySuperClass();

解决方案是使用Object.create设置继承。它为您提供了一个继承自提供的对象的新对象,但不调用任何构造函数。

MySubClass.prototype = Object.create(MySuperClass.prototype);

现在您有一个分配给MySubClass.prototype继承自的对象MySuperClass.prototype,但您不必实际调用构造函数。


不符合 ES5 的实现将不支持Object.create,但您可以为其制作(部分)垫片。

if (!Object.create) {
    Object.create = function(proto) {
        function F(){}
        F.prototype = proto;
        return new F();
    };
}

同样,这不是一个完整的 shim,但它的模拟刚好足以生成继承的对象,而无需调用引用原型对象的构造函数。

于 2012-11-02T16:06:10.233 回答