2012-06-12 2 views
5

Ich habe einige Probleme mit JavaScript. Ich habe folgenden Code:JavaScript: Das Hinzufügen der geerbten Klasse zum Array funktioniert nicht

<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> 

Das SpecializedControl erbt von der Control-Klasse.

Die Funktion addControl in der Form-Klasse fügt das Steuerelement nur einem Array hinzu.

Das Problem ist, dass, wenn ich mehr als ein SpecializedControl hinzufügen, die Werte im Array Art von überschrieben werden, das heißt, wenn ich auf das erste Element im Array zugreifen, die "Control1" sein sollte, bekomme ich "Control2" . Control1 ist nicht mehr im Array.

Wenn ich die gleiche Funktion mit Control-Objekte als Parameter verwenden, funktioniert alles wie erwartet.

Weiß jemand, warum das passiert und was kann getan werden, um dies zu korrigieren?

Antwort

5

Die Werte im Array werden nicht überschrieben werden ; Das Problem ist, beide Steuerelemente teilen sich die gleiche name Variable. Da die Control-Funktion nur einmal ausgeführt wird, gibt es nur eine name Variable, die jemals deklariert wurde.

Sie haben zwei Hauptoptionen, um dies zu beheben. (1) Machen Sie name eine Instanzvariable, die für jedes einzelne Steuerelement spezifisch ist (z. B. this._name). (2) Führen Sie die Control-Funktion aus dem SpecializedControl-Konstruktor aus. (Eigentlich IMO, für ein ausgewogenes und gründliches Erbenmodell sollten Sie ein bisschen von diesen beiden Methoden machen).

Hier sind drei funktionierende Lösungen. Die ersten beiden verwenden die Optionen (1) und (2). Die dritte kombiniert beide Methoden und ist die Art und Weise, wie ich es tun würde (erfordert aber joi).

Option 1:

function Control(){ 

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

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

Option 2:

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

Option 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

Ich empfehle die zweite Option, den Konstruktor der übergeordneten Klasse im Konstruktor Unterklasse aufrufen. Es scheint das Richtige zu sein. Die erste Option erfordert, dass die Variable 'name' offen gelegt wird, und die dritte Option verwendet eine zusätzliche Bibliothek, die versucht, eine normale klassenbasierte Vererbung als Ersatz für die prototypische Vererbung von JavaScript zu implementieren. –

+0

joi verwendet prototypische Vererbung, nicht klassische Vererbung –

+0

Oh, mein Schlechter. Dennoch ist der '# Name' nur von Konvention her intern und hindert Sie nicht daran, von außen darauf zuzugreifen. Mit Schließungen können Sie wirklich private Variablen haben. –

5

Ihre get/setName Funktionen erhalten/setzen den Wert der name Variablen, die lokal für die Control Konstruktorfunktion ist.

Die einzige Zeit, die Sie diese Funktion aufgerufen haben, war eine Instanz als prototype Objekt SpecializedControl zu erstellen. Jedes Mal, wenn Sie setName von einer SpecializedControl Instanz aufrufen, wird diese einzelne Variable aktualisiert.

So, da die get/setName Methoden, die diese Variable verweisen, in der Prototyp-Kette aller SpecializedControl Instanzen sind, werden sie alle die gleichen name beobachten.


In setName, sollten Sie tun ...

this.name = newName; 

Und in getName, sollten Sie tun ...

return this.name; 
Verwandte Themen