2008-12-31 17 views
7

Vedo un sacco di codice come questo:Convenzione per l'ereditarietà di prototipi in JavaScript

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

Tuttavia, se si fa:

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

Questo è falso. Questo mi sembra fonte di confusione, dato che il costruttore di s è, in effetti, Sub. È convenzionale/meglio fare questo?

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

oppure non importa?

+0

Ho appena eseguito il confronto attraverso una pagina html come alert (s.constructor == Sub) e restituito vero. –

+0

Molte framework regolano la proprietà 'constructor' su indica correttamente il costruttore della sottocategoria. Ho un post che tratta questo e altri problemi nel codice che hai mostrato sopra. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html –

risposta

9

'costruttore' non fa quello che sembra lo fa. Questo, oltre alla sua non-standard, è una buona ragione per non usarlo - bastone con instanceof e prototipo.

Tecnicamente: "costruttore" non è una proprietà dell'istanza "s", è una proprietà dell'oggetto prototipo "Sub" che mostra attraverso. Quando crei la funzione "Sub" in Mozilla, ottieni un oggetto Sub.prototype predefinito di nuova creazione che ha un "costruttore" che punta alla funzione Sub come cortesia.

Tuttavia, si sostituisce il prototipo con una nuova Base(). Il prototipo predefinito originale con il collegamento a Sub è perso; invece, Sub.prototype è un'istanza di Base senza alcuna proprietà di "costruzione" sovrascritta. Quindi:

new Sub().constructor=== 
Sub.prototype.constructor=== 
new Base().constructor=== 
Base.prototype.constructor=== 
Base 

... fino all'oggetto più semplice il cui prototipo non è stato modificato.

È convenzionale/migliore?

Quando si tratta di oggetti/classi JavaScript non esiste una convenzione; il sistema di metaclassi di ogni biblioteca si comporta in modo leggermente diverso. Non ne ho visto uno che scrive "costruttore" su ogni classe derivata manualmente, ma sembra una buona soluzione come qualsiasi se si vuole veramente avere il vero costruttore disponibile; renderà anche il codice compatibile con i browser/motori che non ti danno 'costruttore'.

Prenderei in considerazione l'ipotesi di assegnare un nome diverso, per evitare confusione con la proprietà "costruttore" esistente e con un comportamento diverso.

3

Se si desidera verificare se un oggetto è esattamente un esempio di Sub utilizzare l'instanceof dell'operatore: -

print(s instanceof Sub); 

Se vuoi sapere se un oggetto è un'istanza di Sub o un'istanza di un sub -classe di Sub utilizzare il metodo isPrototypeOf: -

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

grazie per il consiglio, ha senso – Claudiu

+0

Un altro bravo Anthony;) – Rob

1

Sì,

Sub.prototype.constructor = Sub; 

ti permette di utilizzare instanceof ma c'è una soluzione migliore. Guarda qui:, TDD JS Inheritance on GitHub, e trova il modello Ereditarietà della combinazione parassita. Il codice è TDD, quindi dovresti essere in grado di eliminarlo molto rapidamente e quindi cambiare semplicemente i nomi per iniziare. Questo è fondamentalmente ciò che usa YAHOO.lang.extend (fonte: yahoo dipendente e autore di Professional JavaScript di Nicholas Zakas per gli sviluppatori Web, 2a ED, pagina 181). Buon libro tra l'altro (non affiliato in alcun modo!)

Perché? Poiché il modello classico con cui stai lavorando ha vars di riferimento statici (se crei var arr = [1,2] nell'oggetto di base, TUTTE le istanze avranno lettura/scrittura e "condividi lo stato" di "arr"! usa il costruttore che ruba puoi aggirare questo Vedi i miei esempi

Problemi correlati