2011-05-10 21 views
10

Come estenderesti una classe usando CoffeeScript, ma gli argomenti di costruzione sono passati a super?Estendi la classe e passa tutti gli argomenti del costruttore a super

Esempio:

class List extends Array 
    # Some other stuff to make it work... 

list = new List(1,2,3) 

console.log list 
 
[1, 2, 3] 
+0

non sarebbe bello per dividere questa domanda in due separati; il primo per il passaggio generale degli argomenti del costruttore a super, il secondo sul comportamento strano di 'Array'? – Mitja

risposta

8
class List extends Array 
    constructor: -> 
     @push arguments... 

    toString: -> 
     @join('-') 

list = new List(1, 2) 

list.push(3) 

list.toString() 

=>

 
'1-2-3' 
+0

Sarebbe bello avere un modo generico per passare tutti gli argomenti al costruttore dell'oggetto genitore, ma questo fa il lavoro in questo caso :) – Acorn

+1

Poiché l'array non ha un metodo "costruttore", non è possibile ... ma sì , sarebbe bello. =) – jejacks0n

+0

Questo non funziona in modalità rigorosa, poiché "argomenti" non esiste in quel caso. – monokrome

24

In generale, questo funzionerebbe senza codice aggiuntivo; il costruttore genitore è usato se non espressamente sovrascritta:

class A 
    constructor: -> 
    console.log arg for arg in arguments 

class B extends A 

new B('foo') # output: 'foo' 

E il problema non è che la matrice non ha un metodo constructor:

coffee> Array.constructor 
[Function: Function] 

Il problema è solo che Array è semplicemente strano. Mentre gli array sono "solo oggetti" in linea di principio, in pratica vengono archiviati in modo diverso. Pertanto, quando si tenta di applicare quel costruttore a un oggetto che non è un array (anche se supera il test instanceof Array), non funziona.

Quindi, è possibile utilizzare la soluzione di Acorn, ma in questo caso è possibile che si verifichino altri problemi lungo la strada (soprattutto se si passa un List a qualcosa che si aspetta un array vero). Per questo motivo, consiglierei di implementare List come wrapper attorno a un'istanza dell'array, piuttosto che provare a utilizzare l'ereditarietà da un tipo di oggetto nativo.

Visto che siamo in tema, una molto importante chiarimento: Quando si utilizza super di per sé, che fa passaggio tutti gli argomenti! Questo comportamento è preso in prestito da Ruby. Così

class B extends A 
    constructor: -> 
    super 

passerà lungo tutti gli argomenti a A 'costruttore s, mentre

class B extends A 
    constructor: -> 
    super() 

invocherà A' costruttore s con senza argomenti.

+0

Grazie per la fantastica spiegazione! '" Suggerirei di implementare List come wrapper attorno a un'istanza dell'array "' Come andresti a fare questo? Un breve esempio sarebbe molto apprezzato se hai tempo! – Acorn

+0

Bene, intendo solo che il costruttore assomiglierebbe a '@arr = Array :: slice.call argomenti, 0' (metodo standard per convertire un metodo arguments in un oggetto), quindi dovresti implementare ciascuno dei metodi dell'array come semplici pass-through (per esempio 'push: -> @ arr.push.apply arr, argomenti',' toString: -> @ arr.toString() ', ...), e infine aggiungi il tuo' List' metodi. –

+0

Oh wow, passando attraverso ogni metodo individualmente .. che suona un po 'noioso :) – Acorn

-1

Nella mia esplorazione di javascript ho richiesto un modo generico per creare una classe con un numero dinamico di argomenti del costruttore. Come già detto, non funzionerà per array, per quanto ne so, funzionerà solo con le classi di stile coffee-script.

Chiamata di una funzione specifica con un numero di argomenti dinamica è abbastanza facile attraverso .apply

args = [1, 2, 3] 
f = measurement.clone 

f.apply measurement, args 

Una classe può estendere una classe salvata in una variabile. Di conseguenza, possiamo scrivere una funzione che restituisce nuove sottoclassi.

classfactory = (f) -> 
    class extension extends f 

Mettere tutto insieme possiamo creare una funzione che restituisce le nuove sottoclassi in cui noi apply argomenti per il costruttore della classe eccellente.

classwitharguments = (f, args) -> 
    class extension extends f 
     constructor:() -> 
      extension.__super__.constructor.apply @, args 

Per utilizzare questa nuova fabbrica

args = [1, 2, 3] 
instance = new (classwitharguments Measurement, args) 

Pensieri? Commenti? Suggerimenti? Limitazioni a cui non ho pensato? Fammi sapere.

2

L'utilizzo di extends in CoffeeScript prevede che la superclasse sia in CoffeeScript. Se utilizzi una classe non CS, ad es. Array nella domanda originale, quindi potresti incontrare problemi.

Questo ha risolto il caso generale per me. È un po 'un trucco perché usa _super che probabilmente non è destinato ad essere usato nel JS compilato.

class MyClass extends SomeJsLib 

    constructor: -> 
    _super.call @, arg1, arg2 

Oppure, se si desidera solo per passare attraverso gli argomenti del chiamante:

class MyClass extends SomeJsLib 

    constructor: -> 
    _super.apply @, arguments 
Problemi correlati