2013-11-15 3 views
0

я не знаю, как решить следующую проблему JavaScript: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».

Благодаря

+1

Это потому, что числа не на прототипе. Вы используете переменную экземпляра в A и переносите ее с новыми экземплярами B – megawac

+0

Итак, в JavaScript нет реальных «частных» свойств? Является ли решение заменить var number на this.numbers = [] ;? –

+1

У меня нет способа наследования с частными переменными. Вы можете добавить это в конструктор B к 'A.apply (this, arguments)' и я думаю, что ваш код будет работать – megawac

ответ

1

Проблема заключается в том, что когда вы делаете:

B.prototype = new A(); 

Вы устанавливаете B.prototype быть экземпляром А, таким образом, 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, потому что вы назвали суперкласс. Преимущество заключается в том, что теперь вы больше не создавать экземпляры для каждого подкласса и (возможно, более важно) теперь вы можете передать аргументы конструктору:

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

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

Вы не можете иметь этот сценарий в вашей модели наследования.

+0

'B.prototype = Object.create (A.prototype);' и 'A.call (this) 'делает трюк! Благодаря! –

0

У вас есть один «А» экземпляр, и это прототип для «B» конструктора. Таким образом, каждый экземпляр «B» разделяет ту же самую переменную закрытия в экземпляре «A».

Смежные вопросы