Crockford's Prototypal inheritance - Issues with nested objects
javascript, prototypal-inheritance
Solution
There is no inconsistency. Just don't think of nested objects: a direct property of an object is always either on its prototype or an own property. It's irrelevant wheter the property value a primitive or an object.
So, when you do
var parent = {
x: {a:0}
};
var child = Object.create(parent);
`child.x` will be referencing the same object as `parent.x` - that one `{a:0}` object. And when you change a property of it:
var prop_val = child.x; // == parent.x
prop_val.a = 1;
both will be affected. To change a "nested" property independently, you first will have to create an independent object:
child.x = {a:0};
child.x.a = 1;
parent.x.a; // still 0
What you can do is
child.x = Object.create(parent.x);
child.x.a = 1;
delete child.x.a; // (child.x).a == 0, because child.x inherits from parent.x
delete child.x; // (child).x.a == 0, because child inherits from parent
which means they are not absolutely independent - but still two different objects.
Problem
I've been reading "Javascript: The Good Parts" by Douglas Crockford - and while it's a bit extreme, I'm on board with a lot of what he has to say. In chapter 3, he discusses objects and at one point lays out a pattern (also found here) for simplifying & avoiding some of the confusion/issues that come with the use of the built-in "new" keyword. ``` if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } newObject = Object.create(oldObject); ``` So I've tried using this in a project I'm working on, and I noticed an issue when attempting to inherit from objects that are nested. If I overwrite a value of a nested object inherited using this pattern, it overwrites the nested element all the way up the prototype chain. Crockford's example is like the `flatObj` in the following example, which works well. The behaviour, however, is inconsistent with nested objects: ``` var flatObj = { firstname: "John", lastname: "Doe", age: 23 } var person1 = Object.create(flatObj); var nestObj = { sex: "female", info: { firstname: "Jane", lastname: "Dough", age: 32 } } var person2 = Object.create(nestObj); var nestObj2 = { sex: "male", info: { firstname: "Arnold", lastname: "Schwarzenneger", age: 61 } } var person3 = { sex: "male" } person3.info = Object.create(nestObj2.info); // now change the objects: person1.age = 69; person2.info.age = 96; person3.info.age = 0; // prototypes should not have changed: flatObj.age // 23 nestObj.info.age // 96 ??? nestObj2.info.age // 61 // now delete properties: delete person1.age; delete person2.info.age; delete person3.info.age; // prototypes should not have changed: flatObj.age // 23 nestObj.info.age // undefined ??? nestObj2.info.age // 61 ``` (also on a fiddle) Am I doing something wrong, or is this a limitation of this pattern?