Devo posizionare funzioni che vengono utilizzate solo in un'altra funzione, all'interno di quella funzione?

28

In particolare, sto scrivendo in JavaScript.

Diciamo che la mia funzione primaria è la funzione A. Se la funzione A effettua diverse chiamate alla funzione B, ma la funzione B non è utilizzata da nessun'altra parte, allora dovrei semplicemente posizionare la funzione B nella funzione A?

Questa è una buona pratica? O dovrei comunque mettere la funzione B allo stesso scopo della funzione A?

    
posta Gary 06.08.2014 - 21:58
fonte

6 risposte

31

Generalmente sono a favore delle funzioni annidate, specialmente in JavaScript.

  • In JavaScript, l'unico modo per limitare la visibilità di una funzione è annidarlo all'interno di un'altra funzione.
  • La funzione di supporto è un dettaglio di implementazione privato. Metterlo allo stesso scopo è come rendere pubbliche le funzioni private di una classe.
  • Se risulta essere di uso più generale, è facile spostarsi fuori, perché puoi essere sicuro che l'helper è attualmente utilizzato solo da quella funzione. In altre parole, rende il tuo codice più coeso.
  • Spesso è possibile eliminare i parametri, il che rende la firma della funzione e l'implementazione meno dettagliate. Non è la stessa cosa che rendere globali le variabili. È più come usare un membro della classe in un metodo privato.
  • Puoi dare le funzioni di aiuto meglio, nomi più semplici, senza preoccuparti dei conflitti.
  • La funzione di supporto è più facile da trovare. Sì, ci sono strumenti che possono aiutarti. È ancora più semplice spostare gli occhi sullo schermo un po '.
  • Il codice forma naturalmente una sorta di albero di astrazione: alcune funzioni generali nella radice, che si diramano in diversi dettagli di implementazione. Se si utilizza un editor con funzione di piegatura / compressione, il raggruppamento crea una gerarchia di funzioni strettamente correlate allo stesso livello di astrazione. Ciò rende molto semplice studiare il codice al livello che ti serve e nascondere i dettagli.

Penso che molta opposizione derivi dal fatto che la maggior parte dei programmatori sono stati portati in una tradizione C / C ++ / Java, o che sono stati insegnati da qualcun altro. Le funzioni annidate non sembrano naturali perché non siamo state esposte a loro molto quando stavamo imparando a programmare. Ciò non significa che non siano utili.

    
risposta data 07.08.2014 - 01:19
fonte
14

Dovresti metterlo allo scopo globale, per diversi motivi.

  • L'annidamento di una funzione di supporto nel chiamante aumenta la lunghezza del chiamante. La lunghezza della funzione è quasi sempre un indicatore negativo; le funzioni brevi sono più facili da capire, da memorizzare, eseguire il debug e mantenere.

  • Se la funzione di aiuto ha un nome ragionevole, leggere quel nome è sufficiente senza dover vedere la definizione nelle vicinanze. Se do ha bisogno di vedere la definizione helper per capire la funzione del chiamante, allora quel chiamante sta facendo troppo o sta lavorando su troppi livelli di astrazione simultaneamente.

  • Avere l'helper globalmente disponibile consente ad altre funzioni di chiamarlo se lo rende generalmente utile dopo tutto. Se l'helper non è disponibile, sei tentato di tagliarlo e incollarlo, o di dimenticarlo e reimplementarlo, male, o di rendere un'altra funzione più lunga di quanto non debba essere.

  • L'annidamento della funzione helper aumenta la tentazione di utilizzare variabili dall'ambito del chiamante senza dichiarazione, in modo che non diventi chiaro quali siano gli input e gli output dell'helper. Se una funzione non indica chiaramente su quali dati opera e quali effetti ha, di solito è un segno di responsabilità non chiare. Dichiarare l'aiuto di un asino una funzione autonoma ti costringe a sapere cosa fa realmente.

Modifica

Questa risultò essere una domanda più controversa di quanto pensassi. Per chiarire:

In JavaScript, le grandi funzioni di estensione dei file spesso soddisfano il ruolo delle classi poiché il linguaggio non fornisce alcun altro meccanismo di limitazione dell'ambito. Sicuramente le funzioni di supporto dovrebbero inserire dentro tali quasi-classi, non al di fuori di esse.

E il punto sul riutilizzo più semplice presuppone che se una subroutine fa diventi più ampiamente usata, sei disposto a spostarla del tutto e metterla in un posto appropriato, ad es. una libreria di utilità di stringa o nel registro di configurazione globale. Se non vuoi ordinare il tuo codice in questo modo, potresti anche nidificare la subroutine, proprio come faresti con un normale Metodo Object in un linguaggio più "blocky".

    
risposta data 06.08.2014 - 22:07
fonte
8

Proporrò un terzo percorso, per inserire entrambe le funzioni all'interno di una chiusura. Sembrerebbe:

var functionA = (function(){
    function functionB() {
        // do stuff...
    }

    function functionA() {
        // do stuff...
        functionB();
        // do stuff...
    }

    return functionA;
})();

Creiamo la chiusura avvolgendo la dichiarazione di entrambe le funzioni in un IIFE . Il valore di ritorno di IIFE è la funzione pubblica, memorizzata in una variabile del nome per la funzione. La funzione pubblica può essere invocata esattamente nello stesso modo in cui è stata dichiarata come funzione globale, ovvero functionA() . Nota che il valore di ritorno è la funzione , non una chiamata alla funzione, quindi nessun paren- sio alla fine.

Inclinando le due funzioni in questo modo, functionB è ora completamente privato e non è possibile accedere al di fuori della chiusura, ma è visibile solo a functionA . Non è ingombrante lo spazio dei nomi globale, e non ingombrano la definizione di functionA .

    
risposta data 07.08.2014 - 05:20
fonte
0

La definizione della funzione B nella funzione A dà accesso alla funzione B alle variabili interne di A.

Quindi, una funzione B definita all'interno di una funzione A dà l'impressione (o almeno la possibilità) che B sta usando o alterando le variabili locali di A. Mentre definire B al di fuori di A rende chiaro che B non lo fa.

Pertanto, per la chiarezza del codice, definirei B all'interno di A solo se B ha bisogno di accedere alle variabili locali di A. Se B ha uno scopo chiaro che è indipendente da A, definirlo definitivamente al di fuori di A.

    
risposta data 16.08.2014 - 16:00
fonte
-1

Non dovresti nidificare, perché altrimenti la funzione annidata verrà ricreata ogni volta che chiami la funzione esterna.

    
risposta data 13.08.2014 - 21:55
fonte
-3

Poiché la funzione B non viene utilizzata da nessun'altra parte, potresti anche renderla una funzione interna all'interno della funzione A perché è l'unica ragione per cui esiste.

    
risposta data 13.08.2014 - 08:39
fonte