2012-04-17 4 views
11

Il seguente codice funziona e, mentre capisco perché funziona, non l'ho visto da nessuna parte. Presumo questo perché tutti gli altri schemi di progettazione sono molto migliori.add (1) (2) (3) .total === 6 - Qualcun altro ha visto funzioni di ritorno automatico utilizzate in questo modo?

Mi sarei comunque aspettato di vedere l'esempio come un ammonimento lungo la linea, ma non l'ho fatto.

Certo, è terribile, soprattutto con l'esempio di sotto del quale ho scelto perché è chiaro ciò che fa, ma:

Cos'è questo modello chiamato?

È comunemente usato?

Esistono progetti legittimi che utilizzano questo modello?

var add = function container (val) { 

    addFunc = function f (val, undefined) { 
    addFunc.total += val; 
    return addFunc; 
    }; 

addFunc.total = 0; 

return addFunc(val); 
}; 

alert(add(1)(2)(3).total); 
alert(add(1)(2)(33).total); 

Modifica: modifica del nome variabile in modo che il codice funzioni in IE.

+1

Questo modello di progettazione sembra un puzzle piuttosto che un codice pulito :) –

+2

Ma PERCHÉ faresti qualcosa del genere ?! –

+3

Questo schema non mi sembra terribile. È molto chiaro da leggere. Credo che preferirei vedere il 'total' come una variabile locale, e la proprietà' .total' come metodo che restituisce il risultato e resetta la variabile. –

risposta

4

Tecnicamente, questo potrebbe essere considerato concatenamento o incapsulamento.

Catena quando è possibile eseguire una serie di operazioni a tempo indeterminato rispetto a una funzione originale. jQuery usa una forma di questo quando puoi concatenare le chiamate per impostare proprietà e attributi su un selettore originale. In questa situazione, il creatore voleva essere in grado di concatenare le chiamate per aggiungere senza dover ridigitare il nome della funzione. Non le idee più pulite, ma valide.

Inoltre, poiché il corpo effettivo del codice non viene mai esposto al chiamante, questo potrebbe anche essere considerato l'incapsulamento poiché il metodo addFunc non è esposto all'ambito esterno.

+0

Io sono il creatore: non l'ho davvero creato con uno scopo, è il risultato di un errore di battitura che ho ripulito in un esempio funzionante, ma il resto di ciò che hai detto è perfetto. Non mi aspettavo di averlo fatto prima per così dire, speravo che avesse un nome, qualcosa con il pop, come "funzione anonima autoinvitante" - c'è un nome che non dimenticherai. – user989370

+0

Dimenticavo: ho visto il metodo concatenare prima (e mi piace molto in jQuery) e capisco perché funzioni, stavo principalmente cercando di capire perché in questo modo e non in un altro. – user989370

1

Si sarebbe infinitamente meglio con:

function add() { 
    var l = arguments.length, i, sum = 0; 
    for(i=0; i<l; i++) sum += arguments[i]; 
    return sum; 
} 
alert(add(1,2,3)); // 6 

Davvero, non ci dovrebbe essere alcun motivo per lo stile del codice che stai chiedendo circa. Non ho visto nessun uso legittimo, solo lunghezza arbitraria arguments.

+0

Penso che il miglioramento più ovvio sia - 1 + 2 + 3. Ovviamente l'esempio per cui l'ho usato è solo illustrazione e non qualcosa che qualcuno avrebbe mai fatto (spero!). Non ne ho davvero bisogno e non l'ho mai usato da solo. – user989370

2

Questo è chiamato Currying wikipedia. Dal nome di Haskell Curry wikipedia (ma originariamente sviluppato da Moses Ilyich Schönfinkel wikipedia).

Una tecnica di trasformazione di una funzione che richiede più argomenti (o una n-tupla di argomenti) in modo tale che possa essere chiamata come una catena di funzioni ciascuna con un singolo argomento (applicazione parziale).

Da JavaScript Patterns forma 2010:

Quando utilizzare Currying - Quando ti ritrovi chiamare la stessa funzione e passando per lo più gli stessi parametri, la funzione è probabilmente un buon candidato per strigliare. È possibile creare dinamicamente una nuova funzione applicando parzialmente una serie di argomenti alla propria funzione. La nuova funzione manterrà i parametri ripetuti memorizzati (in modo da non doverli passare ogni volta) e li userà per pre-compilare l'elenco completo degli argomenti che la funzione originale si aspetta.

Altro article for currying da Dustin Diaz.

4

Questo è un concetto di programmazione funzionale chiamato currying.

In sostanza, dato un function foo(a, b, c) si crea un function bar(a) che restituisce function bar2(b) che restituisce function bar3(c) che dà la risposta definitiva.

Tecnicamente, questo non è vero curriculum perché continua all'infinito e utilizza un effetto collaterale (la proprietà total) per uscire dal ciclo infinito.

Ma in ogni caso, ci possono essere utili applicazioni di questo modello. È particolarmente utile per attraversare strutture ad albero in cui stai calcolando alcuni risultati per ogni foglia dell'albero in cui il risultato dipende dalla discendenza di quella foglia. Si esegue la funzione al curry sul nodo radice e quindi si esegue la funzione restituita su ogni nodo figlio e quindi per ciascuno di tali nodi figlio, ecc. Una funzione pura al curry restituirebbe un'altra funzione se il nodo su cui è in esecuzione ha figli e restituirebbe il valore desiderato se hai raggiunto una foglia.

Il codice sarebbe una semplice funzione ricorsiva che passa a se stesso un nuovo nodo "root" e la funzione per analizzarlo, che richiede sempre un argomento.

Ma, il modo in cui viene utilizzato qui sembra più un esercizio di apprendimento piuttosto che qualcosa di utile.

EDIT: Se si voleva fare una funzione di accattivarsi puro, ma hanno ancora la ricorsione quasi-infinito, i dati di input deve fornire le informazioni di arresto (proprio come un C-string utilizza il valore 0x00 per definire EOF):

var add = (function() { 
    var total = 0; 
    return function nextAdd(a) { 
     if(a != null) { 
      total += a; 
      return nextAdd; 
     } else { 
      return total; 
     } 
    }; 
})(); 

Poi, add(1)(2)(3)(null) === 6 e non c'è nessun parametro .total effetto collaterale.

+0

Poiché l'intero codice può essere sostituito con 1 + 2 + 3, non è stato sicuramente concepito per essere utilizzato in questo modo, ma solo per mostrare che viene effettivamente eseguito. – user989370

+0

Ehi, ho appena aggiunto una versione puramente currying del sommatore per te. –

+0

Grazie per l'esempio: la parte .total è stata imbullonata al mio esempio alla fine per mostrare che funzionava, non era stata pianificata in modo definitivo - Stavo andando per lo più alla velocità con una certa leggibilità. Penso che cercherò di approfondire il curriculum in quanto sembra essere il punto in cui il salto da qui al codice con un uso del mondo reale. – user989370

Problemi correlati