I have the following code (ObjA) and it works as I would expect, instance 'a1' has the same properties as 'a2' but with different values.
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;
debugger info for a1 and a2:
http://www.flickr.com/photos/76617756@N02/6879283032/
Next, I have the following ObjB that inherits from ObjA. Instance 'b1' and 'b2' have the same properties and different values for properties propA and propB but for some reason, objLiteral is the same in both as if it was referencing the same object.
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;
debugger info for b1 and b2:
http://www.flickr.com/photos/76617756@N02/6879283088/
Can somebody help me understand what is happening? What do I have to do to ge what I am expecting? Your help is much appreciated.
Well, both objects b1
and b2
have the same prototype, namely an instance of ObjA
:
ObjB.prototype = new ObjA();
hence they inherit and have access its properties. b1.objLiteral
and b2.objLiteral
refer to the same object:
and
> b1.objLiteral === b2.objLiteral
true
To fix that, you have to create a new object of each instance. This is normally done by calling the "parent" constructor inside the "child" constructor:
function ObjB() {
ObjA.call(this);
this.propB = 2;
}
ObjA.call(this)
will call ObjA
and within that function, this
will refer to the argument passed to call
[MDN], in this case the new instance of ObjB
:
As you can see, objLiteral
is now property of each instance:
> b1.objLiteral === b2.objLiteral
false
To avoid this confusion in the first place, setting an instance of the parent constructor as the prototype of the child constructor should be avoided. What if the parent constructor expects instance specific arguments? What would you pass to ObjA
in this case?
It's better to set the prototype of the child constructor to the prototype of the parent constructor (with one level of indirection) and call the parent constructor like above:
function inherit(Child, Parent) {
var Tmp = function() {};
Tmp.prototype = Parent.prototype;
Child.prototype = new Tmp();
Child.prototype.constructor = Child;
}
inherit(ObjB, ObjA);
Tmp
to prevent extending Parent.prototype
if you extend Child.prototype
later on.
Regarding propA
:
It "works", because you are assigning a new value to it.
Here are again the objects, after assigning properties to x.objLiteral
and x.propA
. You can see that the objects don't have an own objLiteral
property, but an own propA
:
If instead you assign a new value to objLiteral
, e.g. through
b1.objLiteral = {hello: 42};
b1
will now have its own property objLiteral
, which shadows the inherited one: