如果我在Javascript中使用原型继承,则子类中可以使用这些方法,但父级的成员是共享的。这是为什么?
例如,我正在从我的商店扩展2个数据结构类。
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;
现在,如果我使用2个DS1实例,它们将使用相同的商店数据。那是为什么?
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.
答案 0 :(得分:2)
这是使用new
is discouraged for use with prototype
的原因之一。问题是,当您的_data
构造函数运行时,只会创建一个新的唯一Store
数组。您的Store
构造函数仅在DS1.prototype = new Store();
中运行一次。这意味着所有new DS1()
个实例共享相同的_data
数组。
这是一个改编自different answer of mine的相关示例。假设每个Store
都有一个伪唯一的随机id
属性:
var Store = function() {
// each Store instance has a random id
this.id = Math.random();
}
Store.prototype.addData = function() { /* ... */ }
然后,您希望DS1
继承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!
坏消息 - DS1
个实例现在共享相同的id
! DS1.prototype.id
会在DS1.prototype = new Store();
行上设置DS1
,并且所有id
个实例都会从Store
获取DS1
。
相反,您希望每次运行DS1
构造函数代码时运行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);
构造函数代码,而不是在设置{{1}}原型时运行一次:
{{1}}
答案 1 :(得分:2)
This is because in Javascript object are not copied by value but only by reference
。现在,孩子的原型(这里是ds1,ds2)和父母指向同一个对象,当孩子修改原型时,父母会得到改变,兄弟姐妹也是如此。 Inheritance in javascript
可以通过创建空函数F()将其原型设置为父构造函数的原型来实现,如下所示。
function extend(Child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
这样您只需使用extend(ds1, Store)
即可继承; Inheritance and prototype chain
答案 2 :(得分:1)
将Store.call(this)
添加到您的DS1
“类”。之后,您可以开始为构造函数中的DS1
特定属性分配值。
答案 3 :(得分:1)
正如评论中所说,所有孩子都使用相同的对象作为原型。这就是原型继承的作用。
这种继承中的原型对象是子对象的方法和变量的备用存储。
当您从d1
或d2
调用/获取变量时,它会查看是否有addData
。他们没有。然后js进入__prototype。嘿,new Store
在那里!它有addData
吗?是!叫它......
重要的是,new Store
被调用一次,因此创建的对象代表父母的所有孩子。