我使用以下代码获得了意外结果:
var TestModel, u, u2;
function TestModel() {}
TestModel.prototype.a = null;
TestModel.prototype.b = [];
u = new TestModel();
u.a = 1;
u.b.push(1);
u2 = new TestModel();
u2.a = 2;
u2.b.push(2);
console.log(u.a, u.b); // outputs: 1 [1,2]
console.log(u2.a, u2.b); // outputs: 2 [1,2]
我发现令人惊讶的是u.b
和u2.b
包含相同的值,即使TestModel
的每个实例都应该根据我设置原型的方式拥有自己的实例变量。所以这是我期待的输出:
console.log(u.a, u.b); // expecting: 1 [1]
console.log(u2.a, u2.b); // expecting: 2 [2]
如果我将b
设置为对象并在其上设置键而不是将其用作数组,则会发生同样的事情。我在这里不理解什么?
答案 0 :(得分:13)
分配值和引用值之间存在差异。
u.a = 1;
将在a
引用的对象上创建新的u
属性。在分配之前,u.a
将引用TestModel.prototype.a
,但分配新值实际上会在实际对象上创建新属性:
转让后:
另一方面,
u.b.push(1);
将不创建新属性。它将引用现有属性数组,即TestModel.prototype.b
。
即使
TestModel
的每个实例都应该根据我设置原型的方式拥有自己的实例变量
所有实例都引用相同的原型,因此它们引用原型所具有的相同属性。您可以很容易地看到这一点,因为TestMode.prototype === u.b
,TestMode.prototype === u2.b
和u.b === u2.b
都会产生true
。
如果您同时为u.b
和u2.b
分配新值,也会有效:
u.b = [];
通常在构造函数中完成:
function TestModel() {
this.b = [];
}
答案 1 :(得分:3)
原型属性与每个具有自己变量的实例正好相反,原型点是所有实例都自动共享相同的原型属性,因此每个实例都不需要重新定义函数。
您希望每个实例都有这样的数组:
function TestModel() {
this.a = null;
this.b = [];
}
答案 2 :(得分:1)
在两种情况下,数组都是完全相同的数组,即您设置为原型的数组。这意味着两个.push
调用都在该数组上执行,因此所有这些调用都是[1, 2]
:
TestModel.prototype.b
u.b
u2.b
他们都指的是同一财产。
Prototype通常用于函数,因此所有实例都共享相同的函数。如果您要修改原型属性,那么它们也将反映在所有实例中,在这种情况下可能是不合需要的。如果每个实例都应该有一个自定义数组,那么还要为每个实例声明一个自定义数组而不是原型。