我有以下代码 (ObjA),它按我预期的方式工作,实例“a1”具有与“a2”相同的属性,但具有不同的值。
function ObjA() {
this.objLiteral = {};
this.propA = 0;
}
var a1 = new ObjA();
a1.objLiteral['hello'] = 3;
a1.propA = 1.5;
var a2 = new ObjA();
a2.objLiteral['goodbye'] = 4;
a2.propA = 2;
a1 和 a2 的调试器信息:
http://www.flickr.com/photos/76617756@N02/6879283032/
接下来,我有以下继承自 ObjA 的 ObjB。实例“b1”和“b2”具有相同的属性,但属性 propA 和 propB 的值不同,但出于某种原因,objLiteral 在两者中是相同的,就好像它引用的是同一对象一样。
ObjB.prototype = new ObjA();
ObjB.prototype.constructor=ObjB;
function ObjB() {
this.propB = 2;
}
var b1 = new ObjB();
b1.objLiteral['hello2'] = 6;
b1.propA = 4;
b1.propB = 5;
var b2 = new ObjB();
b2.objLiteral['goodbye2'] = 8;
b2.propA = 6;
b2.propB = 7;
b1 和 b2 的调试器信息:
http://www.flickr.com/photos/76617756@N02/6879283088/
有人可以帮助我了解发生了什么吗?我必须做什么才能得到我期望的结果? 非常感谢您的帮助。
最佳答案
好吧,对象 b1
和 b2
都具有相同 原型(prototype),即 ObjA
的实例:
ObjB.prototype = new ObjA();
因此他们继承并可以访问它的属性。 b1.objLiteral
和 b2.objLiteral
引用同一个对象:
和
> b1.objLiteral === b2.objLiteral
true
要解决这个问题,您必须为每个实例创建一个新对象。这通常是通过在“子”构造函数中调用“父”构造函数来完成的:
function ObjB() {
ObjA.call(this);
this.propB = 2;
}
ObjA.call(this)
将调用 ObjA
并且在该函数内,this
将引用传递给 call
[MDN] 的参数,在本例中是 ObjB
的新实例:
如您所见,objLiteral
现在是每个实例的属性:
> b1.objLiteral === b2.objLiteral
false
首先要避免这种混淆,应避免将父构造函数的实例设置为子构造函数的原型(prototype)。如果父构造函数需要实例特定参数怎么办?在这种情况下,您会向 ObjA
传递什么?
最好将子构造函数的原型(prototype)设置为父构造函数的原型(prototype)(具有一级间接),并像上面那样调用父构造函数:
function inherit(Child, Parent) {
var Tmp = function() {};
Tmp.prototype = Parent.prototype;
Child.prototype = new Tmp();
Child.prototype.constructor = Child;
}
inherit(ObjB, ObjA);
Tmp
以防止在您稍后扩展 Child.prototype
时扩展 Parent.prototype
。
关于propA
:
它“有效”,因为您正在为其分配一个新值。
在将属性分配给 x.objLiteral
和 x.propA
之后,这里又是对象。您可以看到对象没有自己的 objLiteral
属性,而是有自己的 propA
:
相反,如果您为 objLiteral
分配一个新值,例如通过
b1.objLiteral = {hello: 42};
b1
现在将拥有自己的属性 objLiteral
,它隐藏了继承的属性:
关于javascript - 继承属性中使用的对象字面量会更改该类的所有实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9917734/