具有意外行为的JavaScript继承

时间:2013-11-15 16:12:16

标签: javascript inheritance constructor

我不知道如何解决以下JavaScript问题:

function A() {
    var numbers = [];

    this.addNumber = function(number) {
        numbers.push(number);
    }

    this.getNumbers = function() {
        return numbers;
    }
}

A.prototype.alertNumbers = function() {
    var numbers = this.getNumbers();
    var length = numbers.length;
    var number;
    var numbersString = "";
    for (var i = 0; i < length; i++) {
        number = numbers[i];
        numbersString += " " + number;
    }
    alert(numbersString);
}

B.prototype = new A();

function B() {
    this.addNumber(1);
    this.addNumber(2);
}

var b = new B();
b.alertNumbers();

var otherB = new B();
otherB.alertNumbers();

工作代码在这里:http://jsfiddle.net/pFxse/

我期待otherB.alertNumbers();也显示“1 2”而不是“1 2 1 2”。

由于

2 个答案:

答案 0 :(得分:1)

问题是当你这样做时:

B.prototype = new A();

您将B.prototype设置为A的实例,因此B.prototype将有2个访问私有变量数的函数。

现在,当您访问(new B()).addNumber()时,您将使用原型中的函数,从而使用原型中的数组。所有实例都将使用该数组。所有实例都将推送到该阵列。

要修复它,就足够了:

function B() {
    A.call(this); // call superclass
    this.addNumber(1);
    this.addNumber(2);
}

通过调用B的构造函数中的超类,您已为B的每个实例创建了一个数字变量,以及包含该变量的2个函数。每个实例都将使用其特定的addNumbers函数,该函数使用其特定的闭包数组。


既然你已经这样做了,你的继承方案也可以简化:

B.prototype = Object.create(A.prototype);

不是创建A类型的新对象并将其设置为B的原型,而是将B的原型设置为直接从A的原型继承。您仍然在A的构造函数中定义了方法,因为您调用了超类。优点是,现在您不再为每个子类创建A的实例,并且(可能更重要)您现在可以将参数传递给构造函数:

function A(name) {
  this.name = name;
}

function B(name) {
  A.call(this, 'B' + name);
}
B.prototype = Object.create(A.prototype);

您的继承模型中不能有这种情况。

答案 1 :(得分:0)

你有一个“A”实例,它是“B”构造函数的原型。因此,每个“B”实例在“A”实例中共享相同的闭包变量。

相关问题