0

If I use prototypical inheritance in Javascript, the methods are available in subclasses but the members from parent are shared. Why is this?

For e.g., I am extending 2 data structure classes from my store.

function Store() {
    this._store = [];
    this._index = -1;
}

Store.prototype.addData = function (val) {
    this._index++;
    this._store[this._index] = val;
};

Store.prototype.toString = function() {
    return "Store: [" + this._store + "]";
};

// inherits from Store
function DS1() {
}

DS1.prototype = new Store();
DS1.prototype.constructor = DS1;

Now if I use 2 instances of DS1, they are using the same store data. Why is that?

var ds1 = new DS1();
ds1.addData(2);
console.log(ds1.toString());  // Prints 2

var ds2 = new DS1();
ds2.addData(3);
console.log(ds2.toString()); // Prints 3

console.log(ds1.toString()); // Prints 3 and NOT 2.
dertkw
  • 7,798
  • 5
  • 37
  • 45
bschandramohan
  • 1,968
  • 5
  • 27
  • 52
  • 1
    *All instances* of DS1 are sharing the same data, because there's only one `DS1.prototype._store` , ever. – apsillers Jun 21 '14 at 07:27
  • No. 2 Different data structures. In Java terms, both DS1 and DS2 extend Store and I expect both to have their own _store array. – bschandramohan Jun 21 '14 at 07:28
  • @aspillers, removed the DS2 which caused confusion. So I have 2 instances of DS1. Why do they share the same data? – bschandramohan Jun 21 '14 at 07:32
  • @apsillers "All instances of DS1 are sharing the same data, because there's only one DS1.prototype._store". Can you explain this more please? When I do DS1.prototype = new Store(); doesn't it mean whenever I do new DS1, all instances have their own _store? – bschandramohan Jun 21 '14 at 07:35
  • 1
    No, because the `DS1` constructor doesn't set a `_store` property. Only the `Store` constructor does that, and you only call it one time, ever. – apsillers Jun 21 '14 at 07:51
  • @apsillers, that helps! is there anyway else I can achieve different instances of _store or is that not recommended/easily possible in Javascript?.. Thanks just saw your answer. – bschandramohan Jun 21 '14 at 07:53
  • 1
    If you'd like to know more about the workings of prototype and the role of the constructor function you can read about it in this answer: http://stackoverflow.com/a/16063711/1641941 – HMR Jun 21 '14 at 14:41

4 Answers4

2

This is one reason why use of new is discouraged for use with prototype. The problem is that a new unique _data array is created only when your Store constructor runs. Your Store constructor only runs one time, ever, in DS1.prototype = new Store(); This means that allnew DS1() instances share the same _data array.

Here's an relevant example adapted from a different answer of mine. Suppose each Store has a pseudo-unique, random id property:

var Store = function() {
    // each Store instance has a random id
    this.id = Math.random();
}
Store.prototype.addData = function() { /* ... */ }

Then, you want DS1 to inherit from Store:

var DS1 = function() {
    this.something = 5;
}
DS1.prototype = new Store();  // this is bad

var ds1 = new DS1();
console.log(ds1.id);

var ds2 = new DS1();
console.log(ds2.id);  // same as ds1!

Bad news -- DS1 instances all share the same id now! DS1.prototype.id is set once, ever, on the line DS1.prototype = new Store();, and that's where all DS1 instances get their id from.

Instead, you want to run the Store constructor code each time you run the DS1 constructor code, instead of just once when your set up the DS1 prototype:

var DS1 = function() {
    Store.call(this);  // set parent constructor properties on `this` new DS1 obj
    //...
}

// DS1 prototype inherits from Store prototype, not Store instance
DS1.prototype = Object.create(Store.prototype);
Community
  • 1
  • 1
apsillers
  • 112,806
  • 17
  • 235
  • 239
2

This is because in Javascript object are not copied by value but only by reference.Now, the prototypes of children (here ds1, ds2) and parents point to same object, when a child modifies the prototype, the parents get the changes and so do the siblings. Inheritance in javascript can be achieve by creating empty function F() setting its prototype to prototype of parent constructor as below.

    function extend(Child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}

This way you can inherit by simply using extend(ds1, Store); Inheritance and prototype chain

Vivek Pratap Singh
  • 9,326
  • 5
  • 21
  • 34
1

Add Store.call(this) to your DS1 "class". After that you can start assigning values for your DS1 specific properties inside the constructor.

1

As it was said in comments, all childs uses the same object as a prototype. That is how prototypical inheritance works.

The prototype object in such kind of inheritance stands as a spare storage of methods and variables for child objects.

When you call/get a var from d1 or d2 it looks if they have addData. They haven't. Then js looks into __prototype. Hey, new Store is there! Does it have a addData? Yes! Calling it...

It's important, that new Store is called once, so a created object stands for all childs of your parent.

ovnia
  • 2,412
  • 4
  • 33
  • 54