2009-12-25 9 views
20

Più mi dedico a javascript, più rifletto sulle conseguenze di determinate decisioni di progettazione e pratiche incoraggiate. In questo caso, sto osservando funzioni anonime, una funzionalità che non è solo fornita da JavaScript, ma che vedo fortemente utilizzata.funzioni anonime considerate dannose?

Credo che siamo tutti d'accordo sui seguenti fatti:

  • la mente umana non si occupa più di 7 più meno di due entità (Miller's law)
  • profonda rientranza è considerato bad programming practice, e sottolinea in generale a problemi di progettazione se si indentano più di tre o quattro livelli. Questo si estende alle entità nidificate, ed è ben presentato nella voce Zen di Python "Flat is better than nested."
  • l'idea di avere un nome di funzione è sia di riferimento che di facile documentazione dell'attività che esegue. Sappiamo, o possiamo aspettarci, che funzione fa removeListEntry(). Il codice chiaro e autodocumentante è importante per il debug e la leggibilità.

Mentre le funzioni anonime sembrano essere una funzionalità molto carina, il suo uso porta a una progettazione del codice profondamente annidata. Il codice è veloce da scrivere, ma difficile da leggere. Invece di essere costretto a inventare un contesto nominato per una funzionalità e ad appiattire la gerarchia di oggetti callable, incoraggia un "go deep level", spingendo il tuo stack di cervello e traboccando rapidamente la regola 7 +/- 2. Un concetto simile è espresso in "About Face" di Alan Cooper, citando liberamente "le persone non capiscono le gerarchie". Come programmatori comprendiamo le gerarchie, ma la nostra biologia limita ancora la nostra comprensione del nidificazione profonda.

Mi piacerebbe sentirti su questo punto. Le funzioni anonime dovrebbero essere considerate dannose, un apparente zucchero sintattico apparente che in seguito si trova in sale o addirittura veleno per topi?

CW in quanto non esiste una risposta corretta.

+0

Cosa intendi considerando le funzioni anonime come "uno zucchero sintattico"? – day

+0

Preferiresti vedere un altro livello di indentazione per una funzione/lambda one-off o dover trovare dove una funzione non anonima si trova al massimo livello? Se la funzione si trova in una posizione diversa, per me è come se fosse un'entità in più da gestire, in cui, come se fosse in linea, fa parte della stessa entità. Se la tua opinione è che è più difficile leggere il codice con funzioni anonime, la mia opinione è che sei strano – Andy

risposta

16

Per come la vedo io, il problema che stai affrontando non sono funzioni anonime, piuttosto una riluttanza a scomporre la funzionalità in unità utili e riutilizzabili. Il che è interessante, perché è più facile riutilizzare la funzionalità in lingue con funzioni di prima classe (e, necessariamente, funzioni anonime) rispetto alle lingue senza.

Se nel codice sono presenti molte funzioni anonime profondamente annidate, suggerirei che potrebbero esserci molte funzionalità comuni che possono essere scomposte in funzioni denominate di ordine superiore (cioè funzioni che prendono o restituiscono (" build ") altre funzioni). Anche le "semplici" trasformazioni delle funzioni esistenti dovrebbero avere un nome se vengono usate spesso. Questo è solo il principio SECCO.

+4

Questo è esattamente. Non c'è nulla di intrinsecamente sbagliato nell'usare funzioni anonime in situazioni in cui hanno senso, ma quando fanno qualcosa di non banale, è meglio mettere la funzionalità reale in una funzione con nome (o più, anche). – mcv

+0

@mvc: in quali situazioni potrebbero avere senso? –

+0

@ToniLeigh: ha senso utilizzare una funzione anonima se (1) è abbastanza breve da essere facilmente compresa e (2) viene utilizzata solo in quel luogo. Per esempio. Io uso "Mi piace" di @backup_filenames = map {"$ _. Bak"} @ filenames' in Perl sempre - il "{" $ _. Bak "}" è una funzione anonima che accetta un argomento, $ _', aggiunge '" .bak "' a esso e restituisce la risposta. 'map' lo applica a tutti gli elementi nell'array' @ nomi file '. –

2

Penso che le chiusure abbiano enormi vantaggi che non dovrebbero essere trascurati. Ad esempio, Apple sfrutta i "blocchi" (chiusure per C) con GCD per fornire un multithreading davvero semplice - non è necessario configurare le strutture di contesto e può semplicemente fare riferimento alle variabili per nome poiché sono nel campo di applicazione.

Penso che un problema più grande con Javascript sia che non ha scope di blocco (i blocchi in questo caso si riferiscono al codice in parentesi graffe, come un'istruzione if). Ciò può portare a enormi complicazioni, costringendo i programmatori a utilizzare chiusure inutili per aggirare questo limite di progettazione di Javascript.

8

Le funzioni anonime sono più utili dal punto di vista funzionale che dannose in modo leggibile. Penso che se si formatta il codice abbastanza bene, non si dovrebbe avere un problema. Non ho problemi con questo, e sono sicuro di non poter gestire 7 elementi, figuriamoci 7 + 2 :)

+0

Cosa significa? "utile dal punto di vista funzionale" Si prega di elaborare. –

+0

Immagino che in questa risposta di 5 anni fa intendessi il compromesso tra l'utilità delle funzioni anonime e la loro leggibilità nel codice preferito per utilizzarle.In altre parole, non dovresti scegliere di non utilizzare le funzioni anonime perché rendono il tuo codice più difficile da leggere perché facilita la scrittura. – Jason

+0

Capisco il compromesso che stavi spiegando. Ma non riesco a capirlo fino a quando non approfondisci ciò che intendi per "utile dal punto di vista funzionale". A meno che non si intenda che le funzioni anonime sono più facili da scrivere? Se é cosi, come? –

4

In realtà, le gerarchie aiutano a superare la regola 7 +/- 2 allo stesso modo di OOP lo fa. Quando scrivi o leggi un corso, leggi il suo contenuto e nulla del codice esterno in modo che tu abbia a che fare con una porzione relativamente piccola di entità. Quando guardi le gerarchie di classi, non guardi dentro di loro, significa che di nuovo hai a che fare con un piccolo numero di entità.

Lo stesso se vero per le funzioni annidate. Dividendo il tuo codice in più livelli di gerarchia, tieni ogni livello abbastanza piccolo da poter essere compreso dal cervello umano.

Le chiusure (o funzioni anonime) aiutano solo a suddividere il codice in un modo leggermente diverso rispetto a quello di OOP, ma in realtà non creano gerarchie.Sono qui per aiutarti a eseguire il tuo codice nel contesto di un altro blocco di codice. In C++ o Java devi creare una classe per questo, nella funzione JavaScript è sufficiente. Certo, la classe standalone è più facile da capire in quanto è semplicemente più semplice per gli umani guardarla come se fosse un blocco autonomo. La funzione sembra essere di dimensioni molto più piccole e il cervello a volte pensa di poterlo comprendere e di codificarlo allo stesso tempo, che di solito è una cattiva idea. Ma puoi allenare il tuo cervello a non farlo :)

Quindi no, non penso che le funzioni anonime siano dannose, devi solo imparare ad affrontarle, come hai imparato ad affrontare le lezioni.

+0

Sì, ma spingendo questo punto di vista, qualsiasi programma sarebbe solo una chiamata profondamente annidata alle funzioni anonime, che è ciò che, penso, i linguaggi funzionali fanno, quindi il)))))))))))))) alla fine di ogni programma LISP. la nidificazione dovrebbe migliorare la leggibilità, ridurre il rientro, mantenere il numero di parentesi nidificate a un minimo gestibile e, in generale, avere un codice auto-descrittivo. Se lo nidifichi, stai praticamente facendo il lavoro del computer: eseguendo una serie di chiamate e nel processo non stai etichettando (quindi descrivendo) qualcosa. –

+0

Codice LISP leggibile e autoreferenziale come qualsiasi codice OOP. Devi solo leggerlo in modo diverso, è un'abilità speciale che devi dedicare del tempo per ottenere. Per esempio, la lingua tedesca è tanto leggibile quanto l'inglese per una persona che li conosce entrambi. La stessa situazione qui. – vava

+0

Tranne che non si ha idea dell'azione che si esegue su un oggetto fino alla fine della frase, qualcosa che è ancora più evidente in giapponese, dove il verbo va _always_ alla fine. Personalmente ritengo che le lingue SVO siano superiori alle lingue SOV e porto la mia opinione ai linguaggi di programmazione. –

-2

Chi ha mai avuto l'idea di richiedere che le funzioni siano associate agli identificatori, ha fatto sì che ogni programmatore fosse un disservizio. Se non hai mai fatto una programmazione funzionale e non hai familiarità con le funzioni e sei a tuo agio con le funzioni di prima classe, non sei un vero programmatore.

In effetti, per contrastare la tua stessa argomentazione, vorrei arrivare fino a considerare le funzioni legate ai nomi (globali) come dannose! Controlla Crockford's article about private and public members e scopri di più.

+1

funziona come entità di prima classe e il fatto che possano essere associati agli identificatori sono concetti separati. In ogni caso, l'associazione di un dato nome descrittivo a una funzione è utile per la documentazione. Se ti do una funzione anonima, non hai modo di comprenderne l'utilizzo a meno che non sbagli dentro e "esegua" la sua logica. Se ti dico che la funzione è associata all'identificatore readFile, ottieni il suo comportamento solo leggendo all'identificatore associato. Questo non è possibile con funzioni anonime, e il vantaggio di non dover dare un nome fa male leggibilità. –

+0

@Stefano: Non penso sia esatto affermare che "funziona come entità di prima classe, e il fatto che possano essere associati agli identificatori sono concetti separati". Per essere in grado di trattare le funzioni come entità di prima classe, devi essere in grado di evitare di dare loro un nome - corretto? Altrimenti non possono essere passati o restituiti da funzioni come valori senza nome come '42',' 6.9' o '" a string "'. E funziona come entità di prima classe è un potente, utile costrutto, sei d'accordo? –

+1

Non è necessario dare un nome a una funzione come 'function (x, y) {return x + y; } '- è utile tanto quanto scrivere' ++ i; // incrementa i'. –

0

Penso anche che le funzioni anonime (nelle ultime lingue spesso definite come chiusure) hanno grandi vantaggi e rendono il codice spesso più leggibile e più breve. A volte sto diventando pazzo quando devo lavorare con Java (dove le chiusure non sono caratteristiche linguistiche di prima classe).

Se il problema è costituito da indentazione e troppe variabili funzione incapsulate, è necessario ridefinire il codice per renderlo più modulare e leggibile.

Per quanto riguarda il java-script, penso che le variabili di funzione siano piuttosto brutte e rendono il codice ingombra (la funzione incapsulata (...) {} stringa rende il codice java-script spesso meno leggibile). Ad esempio preferisco di gran lunga la sintassi di chiusura di groovy ('{}' e '->' caratteri).

3

In modo divertente, JavaScript vi permetterà Nome Funzioni "anonimi":

function f(x) { 
    return function add(y) { 
     return x+y; 
    }; 
} 
+1

Una volta capito che quelle sono le espressioni di funzione ** **, non solo "funzioni anonime", diventa meno divertente;) – kangax

+0

@ Mark Bessey: Non sono sicuro esattamente quello che stai dicendo. La maggior parte delle lingue che ti permettono di produrre valori di tipo funzione (== funzioni anonime) ti consentiranno di associare tali valori con nomi di variabili. Questo equivale ad assegnare il valore "anonimo" 4.2 alla variabile denominata 'x' nell'istruzione C' x = 4.2; '. –

+1

Credo che il punto stavo cercando di fare è che le espressioni di funzione hanno una proprietà nome opzionale, che è ironico per una funzione "anonimo". Ad esempio: var s = function square (x) {return x * x;} che definisce una funzione denominata quadrata e vincola alla varable s. Raramente c'è un buon motivo per non nominare fnctions n Javascript. Il nome della funzione si presenta in tracce dello stack, ad esempio, che può aiutare con il debug. –

0

Se una funzione non è comprensibile senza un nome, il nome è probabilmente troppo lungo. Usa i commenti per spiegare il codice criptico, non fare affidamento sui nomi.

+1

non vengono eseguiti. il codice fa. –

Problemi correlati