简体   繁体   中英

JavaScript inheritance with unexpected behaviour

I don't know how to solve the following JavaScript problem:

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();

The working code is here: http://jsfiddle.net/pFxse/

I'm expecting that otherB.alertNumbers(); also shows "1 2" and not "1 2 1 2".

Thanks

The problem is that when you do:

B.prototype = new A();

You set B.prototype to be an instance of A, thus B.prototype will have 2 functions that access a private variable numbers.

Now when you access (new B()).addNumber() , you will use the function from the prototype and thus the array from the prototype. All instances will use that array. All instances will push to that array.

To fix it it is enough to do:

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

By calling the superclass in B's constructor, you have created a numbers variable for each instance of B, along with 2 functions which enclose over that variable. Each instance will use its specific addNumbers function which uses its specific closured array.


Since you already did that, your inheritance scheme can be simplified as well:

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

Instead of creating a new object of type A and setting that to the prototype of B, you set the prototype of B to inherit directly from the prototype of A. You still have methods defined in A's constructor because you called the superclass. The advantage is that now you no longer create instances of A for each subclass and (perhaps more important) you can now pass arguments to the constructor:

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

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

You can't have this scenario in your inheritance model.

You've got one "A" instance, and it's the prototype for the "B" constructor. Thus, each "B" instance shares that same closure variable in the "A" instance.

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