In their book “Pro Javascript Design Patterns”, Ross Harmes and Dustin Diaz expose a complication of prototypal inheritance in javascript linked to updates of compound “prototypal” properties. By “prototypal” properties I mean properties that belong to one of the prototypes in the object’s prototype chain.
They give the example:
var CompoundObject = {string1: ‘default value’,childObject:{bool: true, num: 10}}var compoundObjectClone = clone(CompoundObject);// Bad! Changes the value of CompoundObject.childObject.num.compoundObjectClone.childObject.num = 5;
They propose a solution in the book that entails using a factory method to creates the inner compound property on the cloned object:
CompoundObject.childObject = CompoundObject.createChildObject();
var compoundObjectClone = clone(CompoundObject);
compoundObjectClone.childObject = CompoundObject.createChildObject();
compoundObjectClone.childObject.num = 5;
To solve the same problem Ben Nadel advocates the use of super constructor call from within the sub-class constructor in order to create all the parent object properties in the child object properties. That is, the child has its own copies of the parent’s properties. His solution works fine even if it is kind of indiscriminate when it comes to which and when a parent property should be created at the child level.
I looked into ”Pro Javascript Design Patterns” and at Ben’s solution and came up with two, albeit less simple, solutions to the same problem.
In one of them, the clone function of “Pro Javascript Design Patterns” is modified to create specified properties of the “prototype object” directly on the child object. This way “prototype-chain walking” stop at the child itself and does not ascend to the prototype object.
In another solution, the prototype object itself is defined by an immediately executed function in the scope of which the problematic property is defined as a var. It’s a closure and it cannot be accessed by “dot notation”. We then return an object literal that contains accessor and mutator functions. The accessor checks if the property accessed is on the object or on it’s prototype. If on the prototype, it returns a copy, not a reference. The mutator sets the property directly on the literal object.
Now, for a longer explanation. Here we have the first attempt at a solution. In it, we use the “clone” function shown in “Pro Javascript Design Patterns” and modify it as such:
function clone(object,instance_members) {
function F() {}
F.prototype = object;
var _f = new F;
_f.prototype = object;
// instance_members specifies those members of the object parameter that are supposed
// to be copied by value instead of by reference.
// We specify instance level member this way. It helps in keeping modifications
// to the similar properties on the prototype to cascade to the copies.
// Members of the object parameter that are not so specified can be thought of
// as shared members.
if(arguments.length>1)
{
if(!(‘[object Array]‘ === Object.prototype.toString.call(instance_members)))
{
throw new Error(“the second argument to clone function must be an array of strings”);
}
for(i=0;i<instance_members.length;i++)
{
_f[instance_members[i]] = deep_copy(object[instance_members[i]]);
}
}
return _f;
}
The modified clone function can be used in this manner:
var CompoundObject = {
string1: ‘default value’,
childObject: {
bool: true,
num: 10
},
getString: function(){
return this.string1;
}
}
var compoundObjectClone = clone(CompoundObject);
//we specify instance level members in the array parameter
var obj2 = clone(CompoundObject,['childObject']);
// Bad! Changes the value of CompoundObject.childObject.num.
// However it will not affect obj2 created earlier since it’s childObject parameter
// is set at the instance level.
compoundObjectClone.childObject.num = 5;
// obj3 is created from the modified compound object.
var obj3 = clone(CompoundObject);
alert(“compoundObjectClone = “+compoundObjectClone.childObject.num)
alert(“obj2 = “+obj2.childObject.num)
alert(“obj3 = “+obj3.childObject.num)
I came up with another solution using closures and the original clone function of ”Pro Javascript Design Patterns”:
var CompoundObject = (function()
{
this.string1 = “default string”;
var childObject = {
bool: true,
num: 10
};
return {
getChildObject: function(){
if(!this.hasOwnProperty(‘childObject’))
{return deep_copy(childObject);}
return this.childObject
},
setChildObject:function(cobj){
this.childObject = cobj;
}
}
})();
In the definition of the object that we want to use as prototype, we define the problematic compound object as a “var” so that it is not visible outside the prototype object’s definition. Moreover we use accessor and mutator methods to manipulate its value.
We can now set the value of the compound object on a child object without changing the prototype property:
var compoundObjectClone = clone(CompoundObject);
var obj2 = clone(CompoundObject);
alert(obj2.getChildObject().num);
var cobj = obj2.getChildObject();
cobj.num=5;
obj2.setChildObject(cobj);
alert(‘obj2.getChildObject().num = ‘+obj2.getChildObject().num);
var obj3 = clone(CompoundObject);
alert(‘obj3.getChildObject().num = ‘+obj3.getChildObject().num);
With this solution, the object used as prototype is responsible for ensuring it’s own integrity.
The deep_copy function used in the code comes from Stephen Chapman

