javascript 继承:实例与原型

javascript inheritance: Instance vs prototype

使用继承时,ChildObject.prototype = new ParentObject();ChildObject.prototype = ParentObject.prototype; 之间有什么区别,哪种方法更好。

我在 Douglas Crockford 的例子中看到了 ChildObject.prototype = new ParentObject();

我们通常使用原型来提供方法 - 以避免为 class 的每个实例重复相同的函数。换句话说,对于类似...

ChildObject.prototype.foo = function() {
  console.log('foo');
};

现在您可能看到了第二种方法的问题:修改 ChildObject.prototype 也会修改 ParentObject.prototype(在 ChildObject.prototype = ParentObject.prototype 行之后是同一个对象)。这意味着此示例中的所有 ParentObject 都将有 foo 方法可供他们使用。实际上,说 ParentObjectChildObjectparent 甚至是不正确的——两者具有相同的原型链。

然而还有另一个令人讨厌的副作用。考虑一下:

function ParentObj() {}
function ChildObj() {}
ChildObj.prototype = ParentObj.prototype;
var i = new ParentObj();
console.log(i); // ParentObj {}
var j = new ChildObj();
console.log(j); // ParentObj {}

看,两个原型,因为它们是同一个对象,具有相同的 constructor 属性。所以为了区分它们,我们必须在构造函数中引入一些标志,从根本上覆盖已经存在的机制。

如果你这样做

ChildObject.prototype = ParentObject.prototype;

那么你的parent和child有相同的原型。对于后者,

ChildObject.prototype = new ParentObject();

child的原型是parent本身。

两者都没有

改为:

ChildObject.prototype = Object.create(ParentObject.prototype);
ChildObject.prototype.constructor = ChildObject;

结合ChildObject开头的这一行:

ParentObject.call(this/*, appropriate args if any*/);

或者如果传递 all args:

ParentObject.apply(this, arguments); // `arguments` literally -- it's provided by the JavaScript engine

ChildObject.prototype = new ParentObject(); 的问题在于,如果 ParentObject 需要参数,它就无法工作,就像许多(大多数?)构造函数那样。因此,该模式在常见(可能是大多数)情况下不起作用。

ChildObject.prototype = ParentObject.prototype; 的问题在于,您让它们都指向 同一个对象 。因此,在 ChildObject.prototype 上设置 属性 会使它显示在 ParentObject 的实例上(因为您刚刚也将其设置在 ParentObject.prototype 上)。

Object.create 版本推迟调用 ParentObject 直到你有一个对象要初始化,但给你一个对象,你可以在上面放置特定于 ChildObject 实例的东西。 (constructor 反向链接是为了使替换对象看起来像 ChildObject 最初的默认对象;这在过去并不重要,但现在在某些情况下 ES6 和一些库实际上使用了它即使 ES5 和更早版本没有使用过它[他们只是把它放在那里]。)

最后:Object.create 的单参数版本可以在 2009 年之前添加到 ES5 中时针对过时的浏览器进行填充,或者如果您不喜欢部分功能,则可以使用工厂函数代替-匀场:

function objectCreate(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor;
}