2012-06-12 2 views
5

У меня возникают некоторые проблемы с JavaScript. У меня есть следующий код:JavaScript: добавление унаследованного класса в массив не работает

<html> 
<head> 
<title>Test</title> 
<script type="text/javascript"> 
function Control(){ 
    var name; 

    this.setName = function(newName){ 
     name = newName; 
    }; 

    this.getName = function(){ 
     return name; 
    }; 
} 

function SpecializedControl(){ 
} 
SpecializedControl.prototype = new Control(); 

function Form(){ 
    var formControls = []; 

    this.addControl = function(control){ 
     formControls.push(control); 

     alert(formControls[0].getName()); 
    }; 
} 

var form = new Form(); 

var control1 = new SpecializedControl(); 
control1.setName("Control1"); 
form.addControl(control1); 

var control2 = new SpecializedControl(); 
control2.setName("Control2"); 
form.addControl(control2); 

</script> 
</head> 
<body> 
</body> 
</html> 

SpecializedControl наследует класс Control.

Функция addControl в классе Form просто добавляет элемент управления в массив.

Проблема заключается в том, что когда я добавляю несколько специализированных контроллеров, значения в массиве являются чрезмерными, это означает, что когда я получаю доступ к первому элементу массива, который должен быть «Control1», я получаю «Control2», , Control1 больше не находится в массиве.

Когда я использую ту же функцию с объектами управления как параметры, все работает так, как ожидалось.

Кто-нибудь знает, почему это происходит и что можно сделать, чтобы исправить это?

ответ

5

Значения в массиве не переопределяется ; проблема заключается в том, что оба элемента управления имеют одну и ту же переменную name. Поскольку функция Control выполняется только один раз, есть только одна переменная name.

У вас есть два основных варианта исправить это. (1) Сделайте name переменной экземпляра, которая является специфической для каждого отдельного элемента управления (например, this._name). (2) Выполните функцию Control внутри конструктора SpecializedControl. (На самом деле, ИМО, для хорошо сбалансированной и тщательной модели наследования вам нужно сделать немного обоих этих методов).

Вот три рабочих решения. Первые два варианта использования (1) и (2) соответственно. Третий объединяет оба метода и способ, которым я это сделаю (но требует joi).

Вариант 1:

function Control(){ 

    this.setName = function(newName){ 
     this._name = newName; 
    }; 

    this.getName = function(){ 
     return this._name; 
    }; 
} 

Вариант 2:

function SpecializedControl(){ 
    Control.apply(this, arguments); 
} 

Вариант 3:

var Control = joi.Unit.sub(function() { 

    function constructor() { 
     this.base(); 
    } 

    constructor.prototype = { 
     '#name': null, 
     setName: function(name) { 
      this['#name'] = name; 
     }, 
     getName: function() { 
      return this['#name']; 
     } 
    }; 

    return constructor; 

}()); 

var SpecializedControl = Control.sub(function() { 

    function constructor() { 
     this.base(); 
    } 

    return constructor; 

}()); 

var Form = joi.Unit.sub(function() { 

    function constructor() { 
     this.base(); 
     this['#formControls'] = []; 
    } 

    constructor.prototype = { 
     '#formControls': null, 
     addControl: function(control) { 
      this['#formControls'].push(control); 
      alert(this['#formControls'][0].getName()); 
     } 
    }; 

    return constructor; 

}()); 

var form = new Form(); 

var control1 = new SpecializedControl(); 
control1.setName("Control1"); 
form.addControl(control1); 

var control2 = new SpecializedControl(); 
control2.setName("Control2"); 
form.addControl(control2);​ 
+1

Я рекомендую второй вариант, вызов конструктора суперкласса в конструкторе подкласса. Кажется, это правильно. Первый вариант требует раскрытия переменной 'name', а третий вариант использует дополнительную библиотеку, которая пытается реализовать обычное наследование на основе классов в качестве замены прототипического наследования JavaScript. –

+0

joi использует прототипное наследование, а не классическое наследование –

+0

О, мой плохой. Тем не менее, '# name' является только внутренним по соглашению и фактически не мешает вам получать доступ к нему извне. С закрытием вы можете иметь действительно частные переменные. –

5

Ваши функции get/setName получают/устанавливают значение переменной name, которое является локальным для функции-конструктора Control.

Единственный момент, когда вы вызывали эту функцию, заключался в создании экземпляра в качестве объекта prototype объекта SpecializedControl. Поэтому каждый раз, когда вы вызывали setName из экземпляра SpecializedControl, эта переменная обновляется.

Так как методы get/setName, ссылающиеся на эту переменную, находятся в цепочке прототипов всех экземпляров SpecializedControl, все они будут наблюдать то же самое name.


В setName, вы должны сделать ...

this.name = newName; 

И в getName, вы должны сделать ...

return this.name; 
Смежные вопросы