1

I have one class and another that inherits property children from the first one.

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

function B() {}
B.prototype = new A();
B.prototype.addChild = function(Child) {
    this.children.push(Child);
};

var b = new B();
b.addChild(new Object());

Strangely, when dumping b to console, it has no item in .children (if property .children exists at all; Chrome/Firefox), but its prototype's .children property get populated. Why is that?

spaxxUnited
  • 625
  • 1
  • 7
  • 16
  • possible duplicate of [Crockford's Prototypal inheritance - Issues with nested objects](http://stackoverflow.com/questions/10131052/crockfords-prototypal-inheritance-issues-with-nested-objects) – Bergi Mar 27 '13 at 01:49
  • Because `b` does not have an own `children` property, but there is a `children` property on its `[[Prototype]]` chain, which is `b->B.prototype->A.prototype`. So the object is added to `A.prototype.children`. – RobG Mar 27 '13 at 01:51
  • See http://stackoverflow.com/questions/8230085/javascript-prototype-property-not-working-as-expected-with-array-and-object-fiel – Crescent Fresh Mar 27 '13 at 01:52

2 Answers2

1

You shouldn´t be using the prototype to store data that is for the instance. When you do this.children, there are no children in B, thus the prototype chain continues to A. As suggested by @Bergi, you should remove:

B.prototype = new A

Try defining:

function A() {
  this.children = [];
}
A.prototype.addChild = function (o) { this.children.push(o)};
var b = new A();
b.addChild({});
pdjota
  • 3,163
  • 2
  • 23
  • 33
  • 2
    But then don't forget to mention that `B.prototype = new A();` is wrong as well (and would cause the same problem again) – Bergi Mar 27 '13 at 01:50
  • Besides B, i wanted to have C,D,E,F.. that all have certain properties with A in common, like `.children`. To me it looks like this can only be done by repeatedly assigning a "new" `.children` property to each `Class.prototype`, right?..due to JS's prototypal inheritance. Its bad, as i need to have duplicate code. – spaxxUnited Mar 27 '13 at 01:55
  • `B.prototype = new A()` is the OP's attempt at inheritance. Saying "remove it" without explaining how to alternatively accomplish inheritance is confusing to the OP (I would think). – Crescent Fresh Mar 27 '13 at 01:58
  • I will definitely need inheritance, and thereby `B.prototype = new A()`. But now i understood it. Thx to @Bergi, @pdjota and all. I have just read _It's ok to assign primitive types to prototype properties, as default values, but objects and arrays should be initialized in the constructor if they are "per instance"._ [Comment by Felix Kling](http://stackoverflow.com/a/8230141/2142490) – spaxxUnited Mar 27 '13 at 02:04
  • I see your point, the original question was why was children being accessed? Thus for the new question of how to do several chainings I would use the other answer. – pdjota Mar 27 '13 at 02:04
1

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);
};
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Ok, i guess thats one way. Another one would be to have `this.children = [];` in B's constructor as well. The more sophisticated approach would be to have the constructor check for objects/arrays on its prototype and create fresh instances. Will check that out. – spaxxUnited Mar 27 '13 at 02:13
  • Can someone please explain why we need `B.prototype = Object.create(A.prototype)` instead of `B.prototype = A.prototype`? Is this because when adding additional methods to `B.prototype` we'd be affecting `A.prototype` too if we didn't use `Object.create()`? Is this the reason? – Sprogz Nov 10 '17 at 10:54
  • @Sprogz [Yes](https://stackoverflow.com/questions/11088365/why-wouldnt-i-use-child-prototype-parent-prototype-rather-than-child-prototype-new-parent) – Bergi Nov 10 '17 at 11:31