在以下代码中:
function Base() {
this.colors = ["red", "green", "blue"];
}
var base = new Base();
var derived1 = Object.create(base);
console.log(derived1.colors); // ["red", "green", "blue"]
var derived2 = Object.create(base);
console.log(derived2.colors); // ["red", "green", "blue"]
derived1.colors.push("white");
console.log(derived1.colors); // ["red", "green", "blue", "white"]
console.log(derived2.colors); // ["red", "green", "blue", "white"]
两个对象派生自Base,derived1和derived2。我们只将元素推送到derived1.colors,但也修改了derived2.colors。我知道这是因为它们共享相同的原型,其属性颜色是引用类型。但是,基类在引用类型中具有属性是很常见的,因此在JavaScript中使用inheritace看起来很危险。
我的问题是:如果可以的话,如何修复有关继承的问题,以便为derived1和derived2制作两个颜色副本?如果没有,在实际产品代码中避免使用它的最佳做法是什么?
答案 0 :(得分:1)
您正在执行var base = new Base();
并将其设置为两个对象(derived1和derived2)的原型。在javascript中,它们被设置为引用,这意味着您对其中一个进行修改,其他引用将获得相同的更改。
通过这样做:
derived1.colors.push("white");
您正在将值推送到原型对象(引用)的属性,该属性在对象上都是相同的。因此,您会看到此行为,因为对象的原型都指向您之前创建的同一对象。
您可以这样做:
var derived1 = Object.create(new Base());
console.log(derived1.colors); // ["red", "green", "blue"]
var derived2 = Object.create(new Base());
console.log(derived2.colors); // ["red", "green", "blue"]
答案 1 :(得分:1)
如果这是一个问题,我建议不要直接公开数组,而是创建一个选择器和mutator(getter和setter)来访问和修改数据。通过这种方式,您可以保证正确级别的完整性和存储状态。
function Base() {
this.colors = function (colors) {
if (colors === undefined) {
return this._colors || (this._colors = ["red", "green", "blue"]);
} else {
this._colors = colors;
}
};
}
var base = new Base();
var derived1 = Object.create(base);
console.log(derived1.colors()); // ["red", "green", "blue"]
var derived2 = Object.create(base);
console.log(derived2.colors()); // ["red", "green", "blue"]
derived1.colors().push("white");
console.log(derived1.colors()); // ["red", "green", "blue", "white"]
console.log(derived2.colors()); // ["red", "green", "blue"]
最大的变化是你必须将颜色称为功能。请参阅JSFiddle for a demo。
如果你知道你不支持旧的JS运行时,你可以使用实际的getter和setter。
function Base() {}
Base.prototype = {
get colors() {
return this._colors || (this._colors = ["red", "green", "blue"]);
},
set colors(val) {
this._colors = val;
}
};