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
How to Pass Command Line Arguments to a Node.Js Program
Change the Url in the Browser Without Loading the New Page Using JavaScript
How to Find the Operating System Details Using JavaScript
Add Inline Style Using JavaScript
Polymer Share Styles Across Elements
Jquery in Chrome Returns "Block" Instead of "Inline"
Call JavaScript Function from Native Code in Wkwebview
Why Doesn't Indexof Work on an Array IE8
How to Round to 1 Decimal Place in JavaScript
Babel 6 Regeneratorruntime Is Not Defined
Read a File One Line At a Time in Node.Js
Incrementing a Date in JavaScript
Performance of CSS Transitions VS. Js Animation Packages
Vue.Js - Add Class to Clicked Button