可以从实例更改原型对象

时间:2011-10-01 19:28:30

标签: javascript inheritance prototype-programming

有人能以合理的方式向我解释:

function One() {}

One.prototype.obj = { key: 'value' };
One.prototype.str = 'string';

var inst1 = new One(),
    inst2 = new One();

// now let’s change some things in our second instance

inst2.obj.key = 'buh!';
inst2.str = 'buh!';

// ok, so what happens to our other instance?

console.log( inst1.str ); // Yields 'string' (unaffected, expected)
console.log( inst1.obj.key ); // Yields 'buh!' (!!)

console.log( One.prototype.obj.key ); // is also 'buh!'

似乎如果原型包含一个对象,那么使用new关键字创建的实例具有该对象,但如果更改它,则还会更改原型对象,从而影响所有实例,如兄弟-inheritance图案...

这是假设工作的方式吗?

2 个答案:

答案 0 :(得分:2)

简而言之,是的。 Javascript不会为您隐式复制对象,因此当您在obj创建对象文字时,One类的所有实例都只是通过引用引用它。相反,您需要在构造函数中动态创建obj对象:

function One(){
  this.obj = {key:'value'};
}

另请参阅:javascript multidimensional object

答案 1 :(得分:2)

实际上,Javascript不会复制原型中的任何内容。您在原型上定义的所有内容只存在一次(在原型本身上)并被重用,因为相同的原型实例将传递给所有对象。

当您访问对象上的属性时,该对象会检查它是否已在其自身上定义。如果是,则返回与该属性关联的值。如果不是,它会将调用委托给它的原型,后者将从现在起对发生的事情负责。这就是为什么Javascript中的“继承”(代码重用)更好地称为委托。

写访问的情况有点不同。如果在对象上设置属性,它将在本地“隐藏”该值。这就是为什么str属性不受影响的原因,它实际上是在inst2对象上定义的。但是,如果您delete inst2.str并执行另一个console.log( inst2.str ),您会发现它会返回旧值。

PS: 如果您想要一种防止这种情况发生的方法,请查看本教程:http://kevlindev.com/tutorials/javascript/inheritance/index.htm

我建议阅读整篇文章,但是如果您只是想让肉看到“创建子类”部分中的KevLinDev.extend函数。