2012-06-12 10 views
5

Mam pewne problemy z JavaScript. Mam następujący kod:JavaScript: Dodawanie odziedziczonej klasy do tablicy nie działa

<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 dziedziczy z klasy sterowania.

Funkcja addControl w klasie Form właśnie dodaje kontrolkę do tablicy.

Problem polega na tym, że gdy dodaję więcej niż jeden SpecializedControl, wartości w tablicy są nieco przesłonięte, co oznacza, że ​​kiedy uzyskuję dostęp do pierwszego elementu w tablicy, który powinien być "Control1", otrzymuję "Control2" . Control1 nie jest już w tablicy.

Kiedy używam tej samej funkcji z obiektami sterowania jako parametrami, wszystko działa zgodnie z oczekiwaniami.

Czy ktoś wie, dlaczego tak się dzieje i co można zrobić, żeby to poprawić?

Odpowiedz

5

Wartości podane w tablicy nie są przesłonięte ; Problem polega na tym, że obie kontrolki mają tę samą zmienną name. Ponieważ funkcja Control jest uruchamiana tylko raz, zawsze deklarowana jest tylko jedna zmienna name.

Masz dwie główne opcje, aby to naprawić. (1) Spraw, aby name była zmienną instancji, która jest specyficzna dla każdego indywidualnego elementu kontrolnego (na przykład this._name). (2) Wykonaj funkcję Control z wnętrza konstruktora . (W rzeczywistości, IMO, dla dobrze zbilansowanego i szczegółowego modelu dziedziczenia powinieneś robić trochę obu tych metod).

Oto trzy działające rozwiązania. Dwie pierwsze opcje użytkowania (1) i (2). Trzeci łączy obie metody i jest sposobem, w jaki bym to zrobił (ale wymaga joi).

Wariant 1:

function Control(){ 

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

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

Opcja 2:

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

Wariant 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

polecam drugą opcję, wywołanie konstruktora nadklasy w konstruktorze podklasy. Wydaje się, że to słuszne. Pierwsza opcja wymaga ujawnienia zmiennej 'name', a trzecia opcja używa dodatkowej biblioteki, która stara się zaimplementować zwykłe dziedziczenie klasowe jako zamiennik prototypowego dziedziczenia JavaScript. –

+0

joi używa prototypowego dziedziczenia, a nie dziedziczenia klasycznego. –

+0

Och, moje złe. Mimo to '# name' jest tylko wewnętrzną konwencją i tak naprawdę nie uniemożliwia dostępu do niego z zewnątrz. Przy zamknięciach możesz mieć naprawdę prywatne zmienne. –

5

Twoje funkcje get/setName uzyskują/ustawiają wartość zmiennej name, która jest lokalna dla funkcji konstruktora .

Jedynym sposobem wywołania tej funkcji było utworzenie instancji jako obiektu prototype obiektu SpecializedControl. Tak więc za każdym razem, gdy wywołałeś setName z instancji SpecializedControl, ta pojedyncza zmienna jest aktualizowana.

Ponieważ metody odwołujące się do tej zmiennej znajdują się w łańcuchu prototypów wszystkich instancji SpecializedControl, wszystkie będą obserwować ten sam obiekt name.


W setName, należy zrobić ...

this.name = newName; 

I getName, należy zrobić ...

return this.name; 
Powiązane problemy