2

i have a base class

function Base(){
    this.children = new Array();
}
Base.prototype.Add = function(child){
    this.children.push(child)
}

function Sub1(){...}
Sub1.prototype = new Base();

function Sub2(){...}
Sub2.prototype = new Base();

so how come when i do

var S1_1 = new Sub1();
var S1_2 = new Sub1();
S1_1.Add(new Sub2());

S1_2 for some reason also has 1 child and contains the same information as the child i added to S1_1?

Travis J
  • 81,153
  • 41
  • 202
  • 273
WindowsMaker
  • 3,132
  • 7
  • 29
  • 46

2 Answers2

6

It's because that's how prototypal inheritance works. All your Sub1 objects inherit from a common Base object. Because the Base object holds the Array, all Sub1 instances share that Array.

In other words, when you ask for the .children property of each Sub1 object, they will see that they don't own such a property, and will therefore look for it on the prototype from which they inherit. Since they inherit from the same prototype object, they use the same Array.


For each Sub1 to have its own Array, you should define it in the Sub1 constructor.

function Base(){
    this.children = new Array();
}
Base.prototype.Add = function(child){
    this.children.push(child); // `this` will be whatever object invoked the method
}

function Sub1(){
    this.children = [];
}
Sub1.prototype = new Base();

function Sub2(){
    this.children = [];
}
Sub2.prototype = new Base();
  • 1
    +1 - "Because the Base object holds the Array" – Travis J Jun 23 '13 at 23:20
  • 1
    Better: Set up the inheritance with `Sub1.prototype = Object.create(Base.prototype);` and call `Base.call(this)` in the child constructors. Using an instance of the parent as prototype only works as long as it does not expect any arguments. – Felix Kling Jun 23 '13 at 23:27
  • @FelixKling IE 8 doesn't seem to have Object.create. I've added handling constructor parameters and not calling the "parent" constructor when setting prototype to this answer: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 Using goog.inherit – HMR Jun 24 '13 at 01:06
  • 1
    @HMR For this simple use case, a [basic polyfill](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#PolyFill) would be enough. – bfavaretto Jun 24 '13 at 02:03
  • @bfavaretto About using polyfill, it changes `for(hh in Object){` in this case maybe not so importaint but the reason why google uses `goog.array.peek = function` instead of Array.prototype.peek. If you polyfil `.create` for Object then `create` will show up in for(hh in myObject) – HMR Jun 24 '13 at 02:20
  • 1
    @HMR No, it won't show up in `for(hh in myObject)`, only in `for(hh in Object)`. It's added as an own property of the Object constructor. – bfavaretto Jun 24 '13 at 02:48
  • @bfavaretto yes you are correct, it will show up in instances when you add it to `Object.prototype`. Since `create` is going to be a static property of Object and not going to be on any of it's instances I guess it is save to do so. Where as the forEach example on mdn could result in unexpected behavior for people re using your code: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach – HMR Jun 24 '13 at 03:36
0

You didn't take ownership/copy of the Base variables defined with this when creating a sub, you can do so with:

function Sub1(){
  Base.call(this);
}

What that code does is calling Base with the Sub1 instance as the this context.

More on prototype behavior can be found here: Prototypical inheritance - writing up

Community
  • 1
  • 1
HMR
  • 37,593
  • 24
  • 91
  • 160