所以我有以下内容:
function A () { this.a = 0; }
function B () { this.b = 0; }
function C () {}
C.prototype = new B();
var c1 = new C();
var c2 = new C();
c1.b = 10;
console.log(c1.b); // 10
console.log(c2.b); // 0
当我将B.b
更改为某个对象时,它似乎为每个新C
存储了相同的对象:
function A () { this.a = 0; }
function B () { this.b = new A(); }
function C () {}
C.prototype = new B();
var c1 = new C();
var c2 = new C();
c1.b.a = 10;
console.log(c1.b.a); // 10
console.log(c2.b.a); // 10 - I want this to be 0
任何人都可以解释发生了什么/问题是什么。
答案 0 :(得分:6)
当你做了
C.prototype = new B();
您没有说“无论何时需要原型,请new B
”。你所说的是“将原型分配给new B()
(这不应该是非常令人惊讶的。)你得到的是:
C.prototype.b.a === 0
每当您执行new C
时,您都不会重复C.prototype
- 您只是链接到它B
objcet:
C.prototype = new B()
^ ^
| |
c1 c2
c1.b === c2.b; //true
您可能知道,对象可以根据您的内容进行更改。因此,当你执行c1.b.a = 4
时,你将进入基础对象并乱用它。
编辑:第一个示例有效,因为属性解析的工作原理。 b
属性不驻留在对象c1
或c2
上。当你说“给我c1.b
”时,js引擎就是这样的:
b
上有c1
个属性吗?不,没有。c1
的原型(实际原型,对象得到的方法和属性 - 在本例中为C.prototype
)b
属性。归还。在实际的js中,这是(spec):
function GetProperty (name, obj) {
while (obj !== null) {
if (obj.hasOwnProperty(name)) {
return obj[name];
}
obj = Object.getPrototypeOf(obj);
}
return undefined;
}
因此,在b
是一个对象的情况下,你拥有一个对象。更改它会像普通对象一样改变它(注意你没有直接分配给c1.b
- 你会看到我的意思)。用箭头解释:
C.prototype.b = 0
^ ^
| |
c1.b c2.b
这很重要,所以我再次强调一下:当你抓住c1.b
时,你会得到一个被操纵的物体,就像任何其他物体一样。为它分配属性就像任何其他普通对象一样,并将其改变......好吧,改变它。
现在,在前一种情况下(c1.b = 10
),您实际上是分配属性。这意味着您要在c1
对象本身上创建键/值配对。因此,在第一步中,我们会查看c1
是否具有属性b
- 并且它具有。用更多箭头解释:
C.prototype.b = 0
^
|
c1.b=10 c2.b
改变后一个例子,我们可以观察到相同的效果:
//changing
c1.b.a = 10;
//to
c1.b = 4;
c2.b !== 4 && c2.b.a === 0; //true
回顾一下:
c1
对象上设置属性。c1
原型上的对象上设置了一个属性,该对象在所有其他C
个对象上进行了变异。答案 1 :(得分:3)
据我所知,这是最新发生的事情:
function A () { this.a = 0; }
function B () { this.b = 0; }
function C () {}
C.prototype = new B();
var c1 = new C();
var c2 = new C();
c1.b = 10;
当您编写c1.b = 10
时,JavaSript将只添加或更改对象b
的本地属性c1
。它并不关心原型是否已经具有属性b
,在这种情况下它仍然完全不受影响。因此:
console.log(c1.b); // 10 --> local property in c1
console.log(c2.b); // 0 --> prototype property
在你的第二个例子中,你正在做一些不同的事情。您没有将属性分配给c1
,而是操纵它的原型,从而影响所有实例:
c1.b.a = 10;
c1
没有属性b
,因此它将从原型对象中获取并添加或更改ITS属性a
。现在c1
和c2
都没有获得本地属性,因此都引用了更改的原型:
console.log(c1.b.a); // 10 --> points to the prototype
console.log(c2.b.a); // 10 --> points to the prototype
可能的解决方案
c1.b = new A();
c1.b.a = 10