简体   繁体   中英

Inheritance of variable doesn't work

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

For eg, 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.

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 all new 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);

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM