JavaScript chiusure


Esempio

Quando viene dichiarata una funzione, le variabili nel contesto della sua dichiarazione vengono catturate nel suo ambito. Ad esempio, nel codice seguente, la variabile x è associata a un valore nello scope esterno, quindi il riferimento a x viene catturato nel contesto della bar :

var x = 4; // declaration in outer scope

function bar() {
    console.log(x); // outer scope is captured on declaration
}

bar(); // prints 4 to console

Uscita campione: 4

Questo concetto di "cattura" dell'ambito è interessante perché possiamo usare e modificare variabili da un ambito esterno anche dopo l'uscita dall'ambito esterno. Ad esempio, considera quanto segue:

function foo() {
    var x = 4; // declaration in outer scope

    function bar() {
        console.log(x); // outer scope is captured on declaration
    }

    return bar;
    
    // x goes out of scope after foo returns
}

var barWithX = foo();
barWithX(); // we can still access x

Uscita campione: 4

Nell'esempio sopra, quando viene chiamato foo , il suo contesto viene catturato nella bar funzioni. Quindi, anche dopo il suo ritorno, la bar può ancora accedere e modificare la variabile x . La funzione foo , il cui contesto è catturato in un'altra funzione, si dice che sia una chiusura .

Dati privati

Questo ci permette di fare alcune cose interessanti, come la definizione di variabili "private" che sono visibili solo per una funzione specifica o un insieme di funzioni. Un esempio forzato (ma popolare):

function makeCounter() {
    var counter = 0;

    return {
        value: function () {
            return counter;
        },
        increment: function () {
            counter++;
        }
    };
}

var a = makeCounter();
var b = makeCounter();

a.increment();

console.log(a.value());
console.log(b.value());

Uscita di esempio:

1
0

Quando viene chiamato makeCounter() , viene salvata un'istantanea del contesto di tale funzione. Tutto il codice all'interno di makeCounter() utilizzerà makeCounter() nella loro esecuzione. Due chiamate di makeCounter() creeranno quindi due diverse istantanee, con la propria copia del counter .

Espressioni di funzioni invocate immediatamente (IIFE)

Le chiusure sono anche utilizzate per prevenire l'inquinamento dello spazio dei nomi globale, spesso attraverso l'uso di espressioni di funzione immediatamente invocate.

Le espressioni di funzione invocate immediatamente (o, forse più intuitivamente, le funzioni anonime autoeseguite ) sono essenzialmente chiusure chiamate subito dopo la dichiarazione. L'idea generale con gli IIFE è di invocare l'effetto collaterale della creazione di un contesto separato accessibile solo al codice all'interno dell'IFE.

Supponiamo di voler essere in grado di fare riferimento a jQuery con $ . Considera il metodo ingenuo, senza usare un IIFE:

var $ = jQuery;
// we've just polluted the global namespace by assigning window.$ to jQuery

Nell'esempio seguente, viene utilizzato un IIFE per garantire che $ sia associato a jQuery solo nel contesto creato dalla chiusura:

(function ($) {
    // $ is assigned to jQuery here
})(jQuery);
// but window.$ binding doesn't exist, so no pollution

Vedere la risposta canonica su Stackoverflow per ulteriori informazioni sulle chiusure.