基类中引用对象时的继承

时间:2013-12-28 01:24:02

标签: javascript oop inheritance

在以下代码中:

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制作两个颜色副本?如果没有,在实际产品代码中避免使用它的最佳做法是什么?

2 个答案:

答案 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;
     }
 };

以下JSFiddle shows getters and setters in action