Crockford'S Prototypal Inheritance - Issues With Nested Objects

Crockford's Prototypal inheritance - Issues with nested objects

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.

B extends A, but B.add populates A.prototype.property

There is only one children array created in your script, but it is referenced by each instance (and even B's prototype) due to inheritance. When you push to it, you will see the changes from everywhere as well.

Instead, give every instance its own array:

function A() {
this.children = [];
}

And also, don't create only one array for all B instances to inherit from with new A - instead, use

function B() {
A.call(this); // do everything the A constructor does on this instance
}
B.prototype = Object.create(A.prototype);
B.prototype.addChild = function(Child) {
this.children.push(Child);
};

JavaScript Object.create -- inheriting nested properties

That happens because anotherPerson.name is an object and it is stored upper in the prototype chain, on the original person object:

//...
var anotherPerson = Object.create(person);
anotherPerson.hasOwnProperty('name'); // false, the name is inherited
person.name === anotherPerson.name; // true, the same object reference

You can avoid this by assigning a new object to the name property of the newly created object:

// create anotherPerson from person
var anotherPerson = Object.create(person);

anotherPerson.name = {
first: 'Stephen',
last: 'Merchant'
};

Javascript Inheritance - Calling a function from another prototype

You need to wire up your properties after the object has been created:

var Ob = function () {
var that = this;

// set the current root to this instance and return the object
this.getA = function() {
that.A.currentRoot = that;
return that.A;
};

this.getB = function() {
that.B.currentRoot = that;
return that.B;
};
};

Ob.prototype.A = {
goB : function () {
var that = this.currentRoot;

console.log('hello');
that.getB().wtf();
}
};

Ob.prototype.B = {
wtf : function () {
var that = this.currentRoot;

console.log(that, this);
}
};

test = new Ob;
test.getA().goB();

A rather dirty hack is to use a privileged method in the parent object to augment the child object and return it so you have access to the parent object via a property. The dirty part is that if you cache the object the property is not guaranteed to have the correct value. So this is more or less a way to do it although you really shouldn't do it this way.

extending Object.create() in javascript

Yes, one very large pitfall: you're stepping on the toes of the definition!

Object.create already takes a second parameter, an object mapping keys to property descriptors.

This one is hard to polyfill in older environments, which is why it's still widely ignored, but when it becomes more ubiquitous, your shim will mismatch the standards pretty badly.

Why is object property changed for all instances?

Use this:

var tileProperty = {
position: { // we will inherit from this
x: null,
y: null,
init: function(x, y) {
this.x = x;
this.y = y;
}
},
init: function(x, y) {
this.name = x.toString() + y.toString();
// create an own Position object for each instance
this.position = Object.create(this.position);
// and initialize it
this.position.init(x, y); // you might inline this invocation of course

},

}


Related Topics



Leave a reply



Submit