2009-05-31 19 views
8

So che ci sono molte domande simili a tonnellate di grandi risposte a questo. Ho provato a guardare i metodi di ereditarietà classica, o quei metodi di chiusura, ecc. In qualche modo ritengo che siano metodi più o meno "di hacking" per me, in quanto non è proprio ciò che il javascript è progettato per fare. (Benvenuto qualcuno mi corregga se sbaglio). OK, finché funziona, soddisfo con il modello di ereditarietà classica come:javascript inheritance

PARENTClass = function (basevar) { do something here; }; 
PARENTClass.prototype = { a: b, c: d}; // prototype is auto gen 

// Inheritance goes here 
CHILDClass = function (childvar) { do something; }; 
CHILDClass.prototype = new PARENTClass(*1); // Actual inheritance to the prototype statement 
// Instance 
CHILDInstance = new CHILDClass(whatever); 

Sopra è in qualche modo, alla mia comprensione l'eredità di JS. Ma uno scenario non ho idea di come implementare, è quello che succede se voglio fare un po 'di inizializzazione durante la creazione dell'oggetto (cioè all'interno del costruttore), e il nuovo oggetto può essere usato subito ... La mia illustrazione sul problema potrebbe non essere troppo chiaro, così mi ha lasciato usare il seguente C# Psuedo di spiegare quello che voglio fare: (. come init elementi dell'interfaccia utente)

class PARENT { 
    public PARENT (basevar) { ... } 
} 
class CHILD : PARENT { 
    public CHILD (basevar) : PARENT (basevar) // constructor of child, and call parent constructor during construct. 
    { ... } 
} 

per qualche ragione, la loro messa nel costruttore sembra il modo migliore per farlo. Qualcuno ha un'idea su come posso farlo.

PS: nel * 1, non ho idea di cosa dovrei mettere lì. PS2: La situazione di cui sopra ho trovato che la libreria jquery.inherit può fare, mi chiedo solo se non usare la libreria può realizzarla. PS3: O la mia comprensione è sbagliata. Poiché javascript non ha lo scopo di imitare OOP (è per questo che lo chiamo hack), qual è la logica "CORRETTA" per implementarlo.

+0

Check this out: http://stackoverflow.com/questions/7486825/javascript-inheritance/12816953#12816953 –

+0

Usa Object.create() per ereditare il prototipo dalla classe base. In questo modo si modifica l'ondulazione della classe base fino alla sottoclasse, ma non viceversa. Maggiori dettagli sul mio blog: http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon

risposta

17

Non è un mod come tale; JavaScript è un linguaggio prototipato, come definito da Wikipedia come dove:

..classes non sono presenti, e il riutilizzo comportamento (noto come ereditarietà in linguaggi basati) viene eseguita mediante un processo di clonazione oggetti esistenti che servono come prototipi.

Come si dice, le classi non vengono utilizzate in JavaScript; ogni oggetto creato viene discusso dal codice JavaScript Object; tutti gli oggetti in JavaScript hanno l'oggetto prototype e tutte le istanze degli oggetti che si creano metodi e proprietà "ereditari" dall'oggetto prototipo dell'oggetto. Dai un'occhiata al riferimento all'oggetto MDC prototype per ulteriori informazioni.

A partire da questo, quando si chiama la linea:

CHILDClass.prototype = new PARENTClass(); 

In questo modo l'oggetto CHILDClass per aggiungere metodi e proprietà per il suo oggetto prototipo dall'oggetto PARENTClass, che crea un effetto simile al concetto di eredità presente in lingue basate su classi. Poiché l'oggetto prototype influisce su ogni istanza creata di tale oggetto, ciò consente ai metodi e alle proprietà dell'oggetto padre di essere presenti in ogni istanza dell'oggetto figlio.

Se si desidera chiamare il costruttore della classe genitore nel costruttore della classe figlia, si utilizza la funzione JavaScript call; ciò consente di chiamare il costruttore della classe genitore nel contesto del costruttore della classe child, quindi impostare le proprietà appena prototipizzate nella classe figlia su ciò che sono impostate come nella classe genitore.

Inoltre, non è necessario inserire nulla in cui sia stato specificato lo *1, poiché tale riga viene semplicemente utilizzata per aggiungere i metodi e le proprietà all'oggetto prototipo della classe figlio; tuttavia, tenete presente che chiama il costruttore della classe genitore, quindi se ci sono degli argomenti che sono fondamentali nell'operazione del costruttore della classe genitore, dovreste controllare che questi siano presenti in modo da evitare errori JavaScript.

+0

Risposta piacevole e completa. Un'ultima cosa da aggiungere .. Nel caso in cui, ad esempio, quando si chiama il costruttore del genitore, qualcosa, che potrebbe essere fata costoso (come la lettura da XML) o user-aware (come avviso di chiamata) verrà eseguito. Anche io non metto niente in * 1, che in pratica sarebbe ancora eseguito; A meno che non inserisca esplicitamente il controllo nel genitore (ad esempio, if (arguments.length == 0) return;). È una soluzione "corretta" a questo? Scusate che sono venuto da uno sfondo OOP rigoroso, non mi sono ancora veramente abituato alla logica di programmazione js oriented. – xandy

+0

Sì, è così che lo farei: se qualcuno crea un'istanza del tuo oggetto che richiede gli argomenti, non vuoi comunque eseguire quelle azioni. –

10

È possibile richiamare manualmente il costruttore genitore nel costruttore della sottoclasse in questo modo:

CHILDClass = function (basevar) { 
    PARENTClass.call(this, basevar); 
    // do something; 
}; 

Il trucco sta usando il metodo call, che consente di richiamare un metodo nel contesto di un oggetto diverso. Vedi the documentation of call per maggiori dettagli.

+0

Ho cercato dappertutto questa funzionalità. Non l'ho mai visto così semplice. La mia domanda è, è un modo "accettabile" di farlo? Come in, sarebbe considerato un hack? Inoltre, è questa corrente, come in non deprecato come '__proto__'? –

1

JavaScript non ha il supporto integrato per le gerarchie di ereditarietà in quanto l'estensione di tipo dovrebbe essere eseguita tramite aggregazione, ovvero l'aggiunta della funzionalità desiderata direttamente all'oggetto stesso o al suo prototipo se la proprietà deve essere condivisa tra le istanze.

Tuttavia, JS è abbastanza potente da rendere possibile l'implementazione di altre forme di costruzione di oggetti, inclusa l'ereditarietà classica.

Data una clone function - che è sufficiente per aggiungere 'vero' eredità prototipo, e non imbastardimento di JavaScript artificiali - la vostra exampe può essere implementato in questo modo:

function ParentClass(baseVar) { 
    // do stuff 
} 

// don't overwrite the prototype object if you want to keep `constructor` 
// see http://joost.zeekat.nl/constructors-considered-mildly-confusing.html 
ParentClass.prototype.a = 'b'; 
ParentClass.prototype.c = 'd'; 

function ChildClass(childVar) { 
    // call the super constructor 
    ParentClass.call(this, childVar); 
} 

// don't inherit from a ParentClass instance, but the actual prototype 
ChildClass.prototype = clone(ParentClass.prototype); 
ChildClass.prototype.e = 'f'; 

E 'anche possibile aggiungere un po' di zucchero sintattico per la classe ereditarietà basata - la mia propria implementazione can be found here.

L'esempio dall'alto sarebbe quindi leggere

var ParentClass = Class.extend({ 
    constructor: function(baseVar) { 
     // do stuff 
    }, 
    a: 'b', 
    c: 'd' 
}); 

var ChildClass = ParentClass.extend({ 
    e: 'f' 
}); 
1

Ho un javascript OOP wrapper che fornisce 'Classe-like' eredità in cui è possibile sostituire i metodi di base o chiamare i costruttori di base o membri leggero.

di definire le classi in questo modo:

//Define the 'Cat' class 
function Cat(catType, firstName, lastName) 
{ 
    //Call the 'Animal' constructor. 
    Cat.$baseNew.call(this, firstName, lastName); 

    this.catType = catType; 
} 
//Extend Animal, and Register the 'Cat' type. 
Cat.extend(Animal, { type: 'Cat' }, { 
    hello: function(text) 
    { 
     return "meaoow: " + text; 
    }, 
    getFullName: function() 
    { 
     //Call the base 'Animal' getFullName method. 
     return this.catType + ": " + Cat.$base.getFullName.call(this); 
    } 
}) 

//It has a built-in type system that lets you do stuff like: 

var cat = new Cat("ginger", "kitty", "kat"); 
Cat.getType()      // "Cat" 
cat.getBaseTypesAndSelf()   // ["Cat","Animal","Class"] 
cat.getType()      // "Cat" 
cat.isTypeOf(Animal.getType()) // "True" 

var dynamicCat = Class.createNew("Cat", ["tab","fat","cat"]) 
dynamicCat.getBaseTypesAndSelf() // ["Cat","Animal","Class"] 
dynamicCat.getFullName()   // tab: fat cat 

codice sorgente disponibile presso: Class.js

Ho anche maggiori dettagli nel mio blog post su OOP in javascript

1

Ho pensato di citare alcuni dei problemi con il modello classico che stai cercando:

  1. Le variabili di riferimento sulle super classi saranno disponibili come essenzialmente statiche su TUTTE le istanze. Ad esempio, se hai var arr = [1,2,3] nel super, e fai instance_1.arr.push (4) instance_2.arr.push (5) TUTTE queste istanze "vedranno" le modifiche.
  2. Quindi risolvi il problema con la soluzione di Ayman che Zakas chiama "Costruttore che ruba", ma ora chiami due volte il costruttore: una volta per il tuo prototipo e una volta per il furto del costruttore. Soluzione - per il tuo prototipo usa un helper come inheritPrototype (ho mostrato l'intera implementazione di questo in questo post: inheritPrototype method FWIW, essenzialmente derivante da una combinazione di pagina 181 del libro di Zakas e alcuni studi di Crockford.

  3. Nessuna privacy (ma poi di nuovo, avresti bisogno di usare qualcosa come il modello oggetto durevole per ottenere questo e che non può essere quello che vuoi) definizione

  4. oggetto viene lasciato "penzoloni": Soluzione - metti un'istruzione if per controllare le funzioni del tuo prototipo e poi definisci il prototipo con un prototipo letterale.

Ho degli esempi in esecuzione di tutto questo su github !!!

Per me è stata davvero una vera sfida lanciare entrambi: i libri di Zakas e Crockford sulla creazione di oggetti e sull'eredità. Avevo anche bisogno di provare diversi framework TDD JavaScript. Così ho deciso di creare un saggio su TDD Frameworks e la creazione di oggetti JavaScript & Ereditarietà. Ha test di codice in esecuzione e jspec! Ecco il link: * My GitHub Open Source Essay/Book