2008-12-31 8 views
7

ich viel Code wie folgt sehen:Konvention zum Prototypvererbung in JavaScript

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 

Wenn Sie jedoch tun:

s = new Sub(); 
print(s.constructor == Sub); 

Das ist falsch. Das scheint mir verwirrend, da der Konstruktor von s tatsächlich Sub ist. Ist es konventionell/besser, dies zu tun?

function Base() {} 
function Sub() {} 
Sub.prototype = new Base(); 
Sub.prototype.constructor = Sub; 

oder ist es nicht wirklich wichtig?

+0

Ich habe gerade den Vergleich über eine HTML-Seite als Alert (s.constructor == Sub) und es zurückgegeben wahr –

+0

Viele Frameworks anpassen die 'Konstruktor'-Eigenschaft zu Zeigen Sie auf den Konstruktor der Unterklasse. Ich habe einen Beitrag, der sich mit diesem und anderen Problemen in dem Code befasst, den Sie oben zeigten. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html –

Antwort

9

‚Konstruktor‘ nicht tut, was es sieht aus wie es funktioniert. Dies ist, zusätzlich zu seiner Nicht-Standardität, ein guter Grund, es zu vermeiden - bei Instanz und Prototyp zu bleiben.

Technisch: 'Konstruktor' ist keine Eigenschaft der 's' Instanz, es ist eine Eigenschaft des 'Sub' Prototyp-Objekts, die durchgeht. Wenn Sie die Funktion "Sub" in Mozilla erstellen, erhalten Sie ein neugebildetes Standard-Sub.prototype-Objekt, das einen 'Konstruktor' hat, der zurück auf die Sub-Funktion verweist.

Allerdings ersetzen Sie dann diesen Prototyp mit einem neuen Base(). Der ursprüngliche Standardprototyp mit der Verbindung zurück zu Sub ist verloren gegangen; Stattdessen ist Sub.prototype eine Instanz von Base ohne überschreibende Konstruktoreigenschaft. Also:

... bis hinunter zum grundlegendsten Objekt, dessen Prototyp Sie nicht geändert haben.

Ist es konventionell/besser, dies zu tun?

Beim Umgang mit JavaScript-Objekten/-Klassen gibt es keine Konvention; Das Metaklassensystem jeder Bibliothek verhält sich etwas anders. Ich habe keine gesehen, die 'Konstruktor' für jede abgeleitete Klasse manuell schreibt, aber es scheint so gut wie eine Lösung zu sein, wenn Sie wirklich den echten Konstruktor verfügbar haben wollen; Es macht den Code auch kompatibel mit Browsern/Engines, die Ihnen keinen Konstruktor geben.

Ich würde es jedoch in Betracht ziehen, einen anderen Namen zu vergeben, um eine Verwechslung mit der vorhandenen und andersartigen "Konstruktor" -Eigenschaft zu vermeiden. Ja

3

Wenn Sie testen wollen, ob ein Objekt genau eine Instanz von Sub verwenden Sie die instanceof Betreiber: -

print(s instanceof Sub); 

Wenn Sie wissen wollen, ob ein Objekt eine Instanz von Sub oder eine Instanz eines Unter -Klasse von Sub verwenden sie die isPrototypeOf Methode: -

print(Sub.prototype.isPrototypeOf(s)); 
+0

danke für den Hinweis, es macht Sinn – Claudiu

+0

Ein anderer guter Anthony;) – Rob

1

,

Sub.prototype.constructor = Sub; 

können Sie die verwenden Instanceof aber es gibt eine bessere Lösung. Schaue hier:, TDD JS Inheritance on GitHub, und finde die Parasitäre Kombination Vererbung Muster. Der Code ist TDD'd, also sollten Sie in der Lage sein, es sehr schnell zu knacken und dann einfach die Namen ändern, um Sie zu beginnen. Dies ist im Grunde, was YAHOO.lang.extend verwendet (Quelle: Yahoo-Mitarbeiter und Autor Nicholas Zakas Professional JavaScript für Web-Entwickler, 2. ED, Seite 181). Gutes Buch übrigens (in keiner Weise verbunden!)

Warum? Da das klassische Muster, mit dem Sie arbeiten, statische Referenzvars hat (wenn Sie var arr = [1,2] im Basisobjekt erstellen, haben ALLE Instanzen Lese-/Schreibrechte und "teilen" den Status von "arr"! Wenn Sie Verwenden Sie Konstruktor Stehlen können Sie umgehen das. Sehen Sie meine Beispiele.