我有以下代码(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/
有人可以帮我理解发生了什么吗?我该怎么办才能满足我的期望? 非常感谢您的帮助。
答案 0 :(得分:3)
嗯,对象b1
和b2
都有相同的原型,即ObjA
的实例:
ObjB.prototype = new ObjA();
因此他们继承并访问其属性。 b1.objLiteral
和b2.objLiteral
引用相同的对象:
和
> b1.objLiteral === b2.objLiteral
true
要解决此问题,您必须为每个实例创建一个新对象。这通常是通过调用“child”构造函数中的“parent”构造函数来完成的:
function ObjB() {
ObjA.call(this);
this.propB = 2;
}
ObjA.call(this)
将调用ObjA
,在该函数中,this
将引用传递给call
[MDN]的参数,在本例中为ObjB
的新实例:
如您所见,objLiteral
现在是每个实例的属性:
> b1.objLiteral === b2.objLiteral
false
为了避免这种混淆,应该避免将父构造函数的实例设置为子构造函数的原型。如果父构造函数需要特定于实例的参数怎么办?在这种情况下,你会传递给ObjA
什么?
最好将子构造函数的原型设置为父构造函数的 prototype (具有一个间接级别),并像上面一样调用父构造函数:
function inherit(Child, Parent) {
var Tmp = function() {};
Tmp.prototype = Parent.prototype;
Child.prototype = new Tmp();
Child.prototype.constructor = Child;
}
inherit(ObjB, ObjA);
如果您稍后延长Tmp
,则 Parent.prototype
阻止延长Child.prototype
。
关于propA
:
它“有效”,因为你要为它分配一个新值。
在将属性分配给x.objLiteral
和x.propA
之后,再次出现这些对象。您可以看到对象没有自己的objLiteral
属性,而是自己的propA
:
相反,如果您将新值分配给objLiteral
,例如通过
b1.objLiteral = {hello: 42};
b1
现在将拥有自己的属性objLiteral
,它会隐藏继承的属性: