2009-09-28 7 views
8

Ich mache objektorientierte Programmierung in JavaScript ohne Prototype/jQuery (ich benutze jQuery für andere Sachen). Es hat bisher gut funktioniert, aber ich stieß auf ein Problem mit der Vererbung. Wenn ich Objekte in einem Konstruktor deklariere, werden sie grundsätzlich zwischen Instanzen geteilt. Im Folgenden sind einige Codebeispiel:Javascript-Vererbung - im Konstruktor deklarierte Objekte werden zwischen Instanzen geteilt?

A = function() 
    { 
     this.y = new Array(); 
    } 

    A.prototype.doStuff = function(n) 
    { 
     this.y.push(n); 
    } 

    B = function() 
    { 
    } 

    B.prototype = new A(); 

    var b1 = new B(); 
    var b2 = new B(); 

    b1.doStuff(100); 
    b2.doStuff(200); 

    console.log("b1:"); 
    console.log(b1); 
    console.log("b2:"); 
    console.log(b2); 

Dies gibt ein Array [100, 200] sowohl für b1 und b2. Was ich will, ist für b1 und b2 ihre eigenen, separaten Arrays für y zu haben. Wie gehe ich vor?

(PS. Ich gehe davon aus, dass Prototype Klassensystem hat dafür etwas eingebaut. Allerdings würde ich lieber nicht ein Bündel von meinem Code neu schreiben, dass die Klasse-System zu verwenden)

Antwort

7

Das Problem ist, dass Ihre A Konstruktorfunktion für alle B Instanzen nur einmal ausgeführt wird, und so ist this.y ein Verweis auf nur einem Array. Jede Referenz von B wird über die Prototyp-Kette zu der einzigen zentralen A Referenz aufgelöst, die nur eine y hat. Dies ist eine sehr nützliche Funktion, nur nicht für das, was Sie hier versuchen.

Die Antwort ist, die Konstruktion von der Initialisierung zu trennen; Der Konstruktor richtet zentrale Ressourcen ein und der Initialisierer initialisiert eine Instanz. So wird das Problem von den meisten "Klassen" -Implementierungen behandelt, die ich für JavaScript gesehen habe. Damit dies funktioniert, müssen Sie für jede Ebene in der Hierarchie ein Mittel bereitstellen, um den Initialisierer der vorherigen Ebene aufzurufen (was auch für andere Methoden nützlich ist) - z. B. Supercalls.

Supercalls sind, warum sind Sie wahrscheinlich besser dran, für so etwas wie Prototype mit: Sie hart sind gut zu tun, und es ist sehr leicht in die „Enkel“ -Problem fallen - eine Lösung, die zu funktionieren scheint , aber endet nur mit einem Elternteil < -Kind Struktur, kein Elternteil < -Kind < -GrandChild Struktur.

Allerdings, wenn Sie Ihren eigenen Vererbungsmechanismus tun, kann this post on supercalls von meinem pathetisch-anämischen Blog hilfreich sein, wie ich in einige dieser Probleme in der Tiefe gehe. Es nimmt eine vereinfachte Version des Vererbungsmechanismus von Prototype, dekonstruiert es ein wenig und spricht über eine Möglichkeit, Supercalls zu tun, die einige Probleme mit den aktuellen Supercalls von Prototype nicht haben. Das kann dir dabei helfen, sie in deinem eigenen Mechanismus zu machen.

+1

Ja - ich habe etwas gemacht, was du in deinem Blogpost beschrieben hast. Grundsätzlich habe ich eine separate 'construct (target)' Funktion, die instanzspezifische Variablen für 'target' initialisiert. Kinder nennen das ihre Superklasse. Nicht besonders hübsch, aber es scheint zu funktionieren. –

2
B.prototype = new A(); 

das schafft nur eine Instanz Eine für jeden B.

Sie könnten, etw wie

B = function() 
{ 
    this.$super = new A(); 
} 


B.prototype.doStuff = function() 
{ 
    return this.$super(args); 
} 


C = function() 
{ 
    this.$super = new B(); 
} 


C.prototype.doStuff = function() 
{ 
    return this.$super(args); 
} 

C.prototype.whoIsMyGrandParent = function() 
{ 
    return this.$super.$super; 
} 

Javascript hat keine wirkliche inheritation betrachten

+0

Das leidet, was ich die „Enkel“ Problem nennen - sobald es ein 'C' ist, das von 'B' leitet, wird es nicht mehr funktionieren, weil es keine Möglichkeit gibt für 'B' beziehen sich auf ' A'. (Auch, FWIW, 'super' ist ein reserviertes Wort in JavaScript.) –

+0

Entschuldigung das ist richtig. Ich habe in meinen Skripten $ super verwendet. Ich sehe dein Enkelkind Problem nicht. – jantimon

+1

Javascript hat Vererbung. Es ist einfach keine klassische Vererbung. Prototypal OO ist eine völlig andere, aber völlig legitime Form von OO. – eyelidlessness

Verwandte Themen