JavaScript Funzione anonima


Esempio

Definizione di una funzione anonima

Quando una funzione è definita, spesso le dai un nome e poi la invocano usando quel nome, in questo modo:

foo();

function foo(){
    // ...
}

Quando si definisce una funzione in questo modo, il runtime Javascript memorizza la funzione in memoria e quindi crea un riferimento a tale funzione, utilizzando il nome che gli è stato assegnato. Questo nome è quindi accessibile nell'ambito corrente. Questo può essere un modo molto conveniente per creare una funzione, ma Javascript non richiede di assegnare un nome a una funzione. Quanto segue è anche perfettamente legale:

function() {
    // ...
}

Quando una funzione è definita senza un nome, è conosciuta come una funzione anonima. La funzione è archiviata in memoria, ma il runtime non crea automaticamente un riferimento ad esso per te. A prima vista, potrebbe sembrare che una cosa del genere non avrebbe alcun senso, ma ci sono diversi scenari in cui le funzioni anonime sono molto convenienti.

Assegnazione di una funzione anonima a una variabile

Un uso molto comune delle funzioni anonime è assegnarle a una variabile:

var foo = function(){ /*...*/ };

foo();

Questo uso di funzioni anonime è trattato più dettagliatamente in Funzioni come variabile

Fornire una funzione anonima come parametro ad un'altra funzione

Alcune funzioni possono accettare un riferimento a una funzione come parametro. Questi sono a volte indicati come "iniezioni di dipendenza" o "callback", perché consentono alla funzione che la chiamata chiama di "richiamare" il codice, offrendoti l'opportunità di cambiare il modo in cui si comporta la funzione chiamata. Ad esempio, la funzione mappa dell'oggetto Array consente di eseguire iterazioni su ciascun elemento di una matrice, quindi creare un nuovo array applicando una funzione di trasformazione a ciascun elemento.

var nums = [0,1,2];
var doubledNums = nums.map( function(element){ return element * 2; } ); // [0,2,4]

Sarebbe noioso, sciatto e inutile creare una funzione con nome, che ingombrerebbe il tuo obiettivo con una funzione necessaria solo in questo luogo e interromperà il flusso naturale e la lettura del tuo codice (un collega dovrebbe lasciare questo codice per trovare il tuo funzione per capire cosa sta succedendo).

Restituzione di una funzione anonima da un'altra funzione

A volte è utile restituire una funzione come risultato di un'altra funzione. Per esempio:

var hash = getHashFunction( 'sha1' );
var hashValue = hash( 'Secret Value' );

function getHashFunction( algorithm ){

    if ( algorithm === 'sha1' ) return function( value ){ /*...*/ };
    else if ( algorithm === 'md5' ) return function( value ){ /*...*/ };

}

Richiamare immediatamente una funzione anonima

A differenza di molti altri linguaggi, lo scope in Javascript è a livello di funzione, non a livello di blocco. (Vedi Funzione Scoping ). In alcuni casi, tuttavia, è necessario creare un nuovo ambito. Ad esempio, è comune creare un nuovo ambito quando si aggiunge codice tramite un tag <script> , piuttosto che consentire la definizione di nomi di variabili nell'ambito globale (che rischia di far scontrare altri script con i nomi delle variabili). Un metodo comune per gestire questa situazione è definire una nuova funzione anonima e quindi invocarla immediatamente, nascondendo le variabili in modo sicuro nell'ambito della funzione anonima e senza rendere il proprio codice accessibile a terze parti tramite un nome di funzione trapelato. Per esempio:

<!-- My Script -->
<script>
function initialize(){
    // foo is safely hidden within initialize, but...
    var foo = '';
}

// ...my initialize function is now accessible from global scope.
// There's a risk someone could call it again, probably by accident.
initialize();
</script>

<script>
// Using an anonymous function, and then immediately
// invoking it, hides my foo variable and guarantees
// no one else can call it a second time.
(function(){
    var foo = '';
}()) // <--- the parentheses invokes the function immediately
</script>

Funzioni anonime autoreferenti

A volte è utile che una funzione anonima sia in grado di riferirsi a se stessa. Ad esempio, potrebbe essere necessario che la funzione si richiami in modo ricorsivo o aggiunga proprietà a se stesso. Se la funzione è anonima, tuttavia, può essere molto difficile in quanto richiede la conoscenza della variabile a cui è stata assegnata la funzione. Questa è la soluzione meno che ideale:

var foo = function(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) foo(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Bad.

L'intento qui era che la funzione anonima chiamasse ricorsivamente se stessa, ma quando il valore di foo cambia, si finisce con un bug potenzialmente difficile da rintracciare.

Invece, possiamo dare alla funzione anonima un riferimento a se stessa dandogli un nome privato, in questo modo:

var foo = function myself(callAgain){
    console.log( 'Whassup?' );
    // Less then ideal... we're dependent on a variable reference...
    if (callAgain === true) myself(false);
};

foo(true);

// Console Output:
// Whassup?
// Whassup?

// Assign bar to the original function, and assign foo to another function.
var bar = foo;
foo = function(){
    console.log('Bad.')
};

bar(true);

// Console Output:
// Whassup?
// Whassup?

Si noti che il nome della funzione è limitato a se stesso. Il nome non è trapelato nello scope esterno:

myself(false); // ReferenceError: myself is not defined

Questa tecnica è particolarmente utile quando si gestiscono le funzioni anonimi ricorsive come parametri di callback:

5
// Calculate the fibonacci value for each number in an array:
var fib = false,
    result = [1,2,3,4,5,6,7,8].map(
        function fib(n){
            return ( n <= 2 ) ? 1 : fib( n - 1 ) + fib( n - 2 );
        });
// result = [1, 1, 2, 3, 5, 8, 13, 21]
// fib = false (the anonymous function name did not overwrite our fib variable)