javascript继承:实例vs原型

javascript inheritance: Instance vs prototype

本文关键字:vs 原型 实例 继承 javascript      更新时间:2023-09-26

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

我在Douglas Crockford的例子中见过ChildObject.prototype = new ParentObject();

无论是

:

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

ChildObject开头的这一行结合:

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

或者如果传递所有参数:

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

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

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

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

然而还有另一个令人讨厌的副作用。想想看:

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;

则父级和子级具有相同的原型。对于后者,

ChildObject.prototype = new ParentObject();

子元素的原型是父元素本身