oriented - javascript object tutorial




Come funzionano le chiusure JavaScript? (20)

Come spiegheresti le chiusure di JavaScript a qualcuno con una conoscenza dei concetti in cui consistono (ad esempio funzioni, variabili e simili), ma non capisce le chiusure stesse?

Ho visto l'esempio Scheme dato su Wikipedia, ma sfortunatamente non è stato d'aiuto.

https://code.i-harness.com


I bambini ricorderanno sempre i segreti che hanno condiviso con i loro genitori, anche dopo che i loro genitori se ne sono andati. Questo è ciò che le chiusure sono per le funzioni.

I segreti per le funzioni JavaScript sono le variabili private

var parent = function() {
 var name = "Mary"; // secret
}

Ogni volta che lo chiami, viene creata la variabile locale "nome" e viene dato il nome "Maria". E ogni volta che la funzione esce, la variabile viene persa e il nome viene dimenticato.

Come puoi immaginare, poiché le variabili vengono ricreate ogni volta che viene chiamata la funzione, e nessun altro le conoscerà, deve esserci un luogo segreto in cui vengono memorizzate. Potrebbe essere chiamato Chamber of Secrets o stack o scope locale ma non ha molta importanza. Sappiamo che sono lì, da qualche parte, nascosti nella memoria.

Ma in JavaScript c'è questa cosa molto speciale che le funzioni che sono create all'interno di altre funzioni, possono anche conoscere le variabili locali dei loro genitori e tenerle per tutto il tempo in cui vivono.

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    // I can also see that "name" is "Mary"
  }
}

Quindi, finché siamo nella funzione genitore, può creare una o più funzioni figlio che condividono le variabili segrete dal luogo segreto.

Ma la cosa triste è che se il bambino è anche una variabile privata della sua funzione genitore, morirebbe anche quando il genitore finirà, e i segreti morirebbero con loro.

Quindi, per vivere, il bambino deve partire prima che sia troppo tardi

var parent = function() {
  var name = "Mary";
  var child = function(childName) {
    return "My name is " + childName  +", child of " + name; 
  }
  return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside 

E ora, anche se Mary "non sta più correndo", il ricordo di lei non è perso e il suo bambino ricorderà sempre il suo nome e altri segreti che hanno condiviso durante il loro tempo insieme.

Quindi, se chiami il bambino "Alice", lei risponderà

child("Alice") => "My name is Alice, child of Mary"

Questo è tutto quello che c'è da dire.


Chiusure di JavaScript per i principianti

Presentato da Morris su Tue, 21.02.2006 10:19. Pubblicato dalla community.

Le chiusure non sono magiche

Questa pagina spiega le chiusure in modo che un programmatore possa capirle - usando il codice JavaScript funzionante. Non è per guru o programmatori funzionali.

Le chiusure non sono difficili da capire una volta che il concetto di base è burrascoso. Tuttavia, è impossibile capire leggendo qualsiasi spiegazione teorica o accademicamente orientata!

Questo articolo è destinato ai programmatori con una certa esperienza di programmazione in un linguaggio tradizionale e che possono leggere la seguente funzione JavaScript:

function sayHello(name) {
  var text = 'Hello ' + name;
  var say = function() { console.log(text); }
  say();
}
sayHello('Joe');

Due brevi riassunti

  • Quando una funzione (foo) dichiara altre funzioni (bar e baz), la famiglia di variabili locali create in foo non viene distrutta quando la funzione viene chiusa. Le variabili diventano semplicemente invisibili al mondo esterno. Foo può quindi abilmente restituire la barra delle funzioni e baz, e possono continuare a leggere, scrivere e comunicare tra loro attraverso questa famiglia di variabili chiuse ("la chiusura") che nessun altro può intromettersi, nemmeno qualcuno che chiama foo di nuovo in futuro.

  • Una chiusura è un modo per supportare funzioni di prima classe ; è un'espressione che può fare riferimento a variabili all'interno del suo ambito (quando è stato dichiarato per la prima volta), essere assegnato a una variabile, essere passato come argomento a una funzione o essere restituito come risultato di una funzione.

Un esempio di chiusura

Il seguente codice restituisce un riferimento a una funzione:

function sayHello2(name) {
  var text = 'Hello ' + name; // Local variable
  var say = function() { console.log(text); }
  return say;
}
var say2 = sayHello2('Bob');
say2(); // logs "Hello Bob"

La maggior parte dei programmatori JavaScript comprenderà come un riferimento a una funzione viene restituito a una variabile ( say2 ) nel codice precedente. Se non lo fai, allora devi guardarlo prima di poter imparare chiusure. Un programmatore che usa C pensa alla funzione come restituire un puntatore a una funzione e che le variabili say e say2 sono ciascuna un puntatore a una funzione.

Esiste una differenza fondamentale tra un puntatore C a una funzione e un riferimento JavaScript a una funzione. In JavaScript, puoi pensare a una variabile di riferimento di funzione che ha sia un puntatore a una funzione che un puntatore nascosto a una chiusura.

Il codice precedente ha una chiusura perché la funzione di function() { console.log(text); } anonima function() { console.log(text); } function() { console.log(text); } è dichiarato all'interno di un'altra funzione, ad sayHello2() in questo esempio. In JavaScript, se si utilizza la parola chiave function all'interno di un'altra funzione, si sta creando una chiusura.

In C e nella maggior parte degli altri linguaggi comuni, dopo che una funzione è tornata, tutte le variabili locali non sono più accessibili perché lo stack-frame è distrutto.

In JavaScript, se dichiari una funzione all'interno di un'altra funzione, le variabili locali della funzione esterna possono rimanere accessibili dopo essere ritornate da essa. Questo è dimostrato sopra, perché chiamiamo la funzione say2() dopo che siamo tornati da sayHello2() . Si noti che il codice che chiamiamo fa riferimento al text variabile, che era una variabile locale della funzione sayHello2() .

function() { console.log(text); } // Output of say2.toString();

Osservando l'output di say2.toString() , possiamo vedere che il codice si riferisce al text variabile. La funzione anonima può fare riferimento al text che contiene il valore 'Hello Bob' perché le variabili locali di sayHello2() sono state segretamente mantenute in vita in una chiusura.

Il genio è che in JavaScript un riferimento alla funzione ha anche un riferimento segreto alla chiusura in cui è stato creato - simile a come i delegati sono un puntatore del metodo più un riferimento segreto a un oggetto.

Altri esempi

Per qualche ragione, le chiusure sembrano davvero difficili da capire quando leggi su di esse, ma quando vedi alcuni esempi, diventa chiaro come funzionano (ci ho messo un po 'di tempo). Raccomando di esaminare attentamente gli esempi finché non capisci come funzionano. Se inizi a utilizzare le chiusure senza comprendere appieno il loro funzionamento, presto creerai alcuni bug molto strani!

Esempio 3

Questo esempio mostra che le variabili locali non vengono copiate - sono mantenute per riferimento. È come se il frame dello stack rimanga vivo nella memoria anche dopo che la funzione esterna esiste!

function say667() {
  // Local variable that ends up within closure
  var num = 42;
  var say = function() { console.log(num); }
  num++;
  return say;
}
var sayNumber = say667();
sayNumber(); // logs 43

Esempio 4

Tutte e tre le funzioni globali hanno un riferimento comune alla stessa chiusura perché sono tutte dichiarate all'interno di una singola chiamata a setupSomeGlobals() .

var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
  // Local variable that ends up within closure
  var num = 42;
  // Store some references to functions as global variables
  gLogNumber = function() { console.log(num); }
  gIncreaseNumber = function() { num++; }
  gSetNumber = function(x) { num = x; }
}

setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 43
gSetNumber(5);
gLogNumber(); // 5

var oldLog = gLogNumber;

setupSomeGlobals();
gLogNumber(); // 42

oldLog() // 5

Le tre funzioni hanno accesso condiviso alla stessa chiusura: le variabili locali di setupSomeGlobals() quando sono state definite le tre funzioni.

Nota che nell'esempio sopra, se richiami setupSomeGlobals() nuovamente, viene creata una nuova chiusura (stack-frame!). Le vecchie variabili gSetNumber , gSetNumber , gSetNumber vengono sovrascritte con nuove funzioni che hanno la nuova chiusura. (In JavaScript, ogni volta che si dichiara una funzione all'interno di un'altra funzione, le funzioni interne vengono / vengono ricreate di nuovo ogni volta che viene chiamata la funzione esterna.)

Esempio 5

Questo esempio mostra che la chiusura contiene tutte le variabili locali che sono state dichiarate all'interno della funzione esterna prima di uscire. Si noti che la variabile alice viene effettivamente dichiarata dopo la funzione anonima. La funzione anonima viene dichiarata per prima e quando viene chiamata tale funzione può accedere alla variabile alice perché alice trova nello stesso scope (JavaScript fa sollevamento delle variabili ). Inoltre sayAlice()() chiama direttamente il riferimento alla funzione restituito da sayAlice() - è esattamente lo stesso di quello che è stato fatto in precedenza ma senza la variabile temporanea.

function sayAlice() {
    var say = function() { console.log(alice); }
    // Local variable that ends up within closure
    var alice = 'Hello Alice';
    return say;
}
sayAlice()();// logs "Hello Alice"

Tricky: nota anche che la variabile say è anche all'interno della chiusura, e potrebbe essere letta da qualsiasi altra funzione che potrebbe essere dichiarata all'interno di sayAlice() , oppure potrebbe essere letta in modo ricorsivo all'interno della funzione interna.

Esempio 6

Questo è un vero trucchetto per molte persone, quindi devi capirlo. Fai molta attenzione se stai definendo una funzione all'interno di un ciclo: le variabili locali della chiusura potrebbero non agire come potresti pensare prima.

Per comprendere questo esempio, devi comprendere la funzione di "sollevamento variabile" in Javascript.

function buildList(list) {
    var result = [];
    for (var i = 0; i < list.length; i++) {
        var item = 'item' + i;
        result.push( function() {console.log(item + ' ' + list[i])} );
    }
    return result;
}

function testList() {
    var fnlist = buildList([1,2,3]);
    // Using j only to help prevent confusion -- could use i.
    for (var j = 0; j < fnlist.length; j++) {
        fnlist[j]();
    }
}

 testList() //logs "item2 undefined" 3 times

La linea result.push( function() {console.log(item + ' ' + list[i])} aggiunge un riferimento ad una funzione anonima tre volte alla matrice dei risultati.Se non si ha familiarità con le funzioni anonime, si pensi a piace:

pointer = function() {console.log(item + ' ' + list[i])};
result.push(pointer);

Notare che quando si esegue l'esempio, "item2 undefined" viene registrato tre volte! Questo perché, proprio come gli esempi precedenti, esiste una sola chiusura per le variabili locali per buildList (che sono result , i e item ). Quando le funzioni anonime sono chiamate sulla linea fnlist[j]() ; usano tutti la stessa chiusura singola e usano il valore corrente per i e l' item all'interno di quella chiusura (dove i un valore di 3 perché il ciclo è stato completato e l' item ha il valore di 'item2' ). Nota che stiamo indicizzando da 0 quindi l' item ha un valore di item2 . E l'i ++ incrementerà i al valore 3 .

Può essere utile vedere cosa succede quando viene utilizzata una dichiarazione a livello di blocco item variabile (tramite la parola chiave let ) invece di una dichiarazione di variabile dell'ambito della funzione tramite la parola chiave var . Se viene apportata questa modifica, ciascuna funzione anonima nel result dell'array ha la propria chiusura; quando viene eseguito l'esempio, l'output è il seguente:

item0 undefined
item1 undefined
item2 undefined

Se la variabile i è anche definita usando let invece di var , l'output è:

item0 1
item1 2
item2 3

Esempio 7

In questo ultimo esempio, ogni chiamata alla funzione principale crea una chiusura separata.

function newClosure(someNum, someRef) {
    // Local variables that end up within closure
    var num = someNum;
    var anArray = [1,2,3];
    var ref = someRef;
    return function(x) {
        num += x;
        anArray.push(num);
        console.log('num: ' + num +
            '; anArray: ' + anArray.toString() +
            '; ref.someVar: ' + ref.someVar + ';');
      }
}
obj = {someVar: 4};
fn1 = newClosure(4, obj);
fn2 = newClosure(5, obj);
fn1(1); // num: 5; anArray: 1,2,3,5; ref.someVar: 4;
fn2(1); // num: 6; anArray: 1,2,3,6; ref.someVar: 4;
obj.someVar++;
fn1(2); // num: 7; anArray: 1,2,3,5,7; ref.someVar: 5;
fn2(2); // num: 8; anArray: 1,2,3,6,8; ref.someVar: 5;

Sommario

Se tutto sembra completamente non chiaro, la cosa migliore da fare è giocare con gli esempi. Leggere una spiegazione è molto più difficile che comprendere esempi. Le mie spiegazioni su chiusure e riquadri, ecc. Non sono tecnicamente corrette: sono semplificazioni grossolane intese a facilitare la comprensione. Una volta terminata l'idea di base, puoi raccogliere i dettagli più tardi.

Punti finali:

  • Ogni volta che si utilizza la function all'interno di un'altra funzione, viene utilizzata una chiusura.
  • Ogni volta che si utilizza eval() all'interno di una funzione, viene utilizzata una chiusura. Il testo che si eval può fare riferimento a variabili locali della funzione, e all'interno di eval si possono anche creare nuove variabili locali usando eval('var foo = …')
  • Quando si utilizza la new Function(…) (il costruttore di funzioni ) all'interno di una funzione, non crea una chiusura. (La nuova funzione non può fare riferimento alle variabili locali della funzione esterna.)
  • Una chiusura in JavaScript è come mantenere una copia di tutte le variabili locali, proprio come erano quando una funzione veniva chiusa.
  • Probabilmente è meglio pensare che una chiusura venga sempre creata solo come una voce di una funzione, e le variabili locali vengono aggiunte a quella chiusura.
  • Un nuovo insieme di variabili locali viene mantenuto ogni volta che viene chiamata una funzione con una chiusura (dato che la funzione contiene una dichiarazione di funzione al suo interno, e un riferimento a quella funzione interna viene restituito o viene mantenuto un riferimento esterno per esso in qualche modo ).
  • Due funzioni potrebbero sembrare che abbiano lo stesso testo sorgente, ma hanno un comportamento completamente diverso a causa della loro chiusura "nascosta". Non penso che il codice JavaScript possa effettivamente scoprire se un riferimento di funzione ha una chiusura o meno.
  • Se si sta tentando di apportare modifiche al codice sorgente dinamico (ad esempio: myFunction = Function(myFunction.toString().replace(/Hello/,'Hola')); ), non funzionerà se myFunction è una chiusura ( naturalmente, non si potrebbe nemmeno pensare di eseguire la sostituzione della stringa del codice sorgente in fase di esecuzione, ma ...).
  • È possibile ottenere dichiarazioni di funzioni all'interno di dichiarazioni di funzioni all'interno di funzioni e mash, e si possono ottenere chiusure a più di un livello.
  • Penso che normalmente una chiusura sia un termine sia per la funzione che per le variabili che vengono catturate. Nota che non uso quella definizione in questo articolo!
  • Sospetto che le chiusure in JavaScript differiscano da quelle normalmente presenti nei linguaggi funzionali.

link

Grazie

Se hai appena appreso chiusure (qui o altrove!), Allora sono interessato a qualsiasi tuo commento su eventuali modifiche che potresti suggerire che potrebbero rendere più chiaro questo articolo. Invia una mail a morrisjohns.com (morris_closure @). Si prega di notare che io non sono un guru su JavaScript, né sulle chiusure.

L'articolo originale di Morris può essere trovato nell'Archivio Internet .


Puoi spiegare chiusure a un bambino di 5 anni? *

Continuo a pensare che la spiegazione di Google funzioni molto bene ed è concisa:

/*
*    When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns.
*
* An important concept to learn in JavaScript.
*/

function outerFunction(someNum) {
    var someString = 'Hey!';
    var content = document.getElementById('content');
    function innerFunction() {
        content.innerHTML = someNum + ': ' + someString;
        content = null; // Internet Explorer memory leak for DOM reference
    }
    innerFunction();
}

outerFunction(1);​

* Domanda AC #


Le chiusure sono semplici:

Il seguente esempio semplice copre tutti i punti principali delle chiusure di JavaScript. *

Ecco una fabbrica che produce calcolatrici che possono aggiungere e moltiplicare:

function make_calculator() {
  var n = 0; // this calculator stores a single number n
  return {
    add: function(a) {
      n += a;
      return n;
    },
    multiply: function(a) {
      n *= a;
      return n;
    }
  };
}

first_calculator = make_calculator();
second_calculator = make_calculator();

first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400

first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000

Il punto chiave: ogni chiamata per make_calculatorcreare una nuova variabile locale n, che continua ad essere utilizzabile da quella calcolatrice adde multiplyfunziona molto dopo i make_calculatorritorni.

Se hai familiarità con gli stack frame, questi calcolatori sembrano strani: come possono continuare ad accedere ndopo i make_calculatorresi? La risposta è immaginare che JavaScript non usi "stack frames", ma usi invece "heap frames", che possono persistere dopo la chiamata alla funzione che li ha fatti restituire.

Le funzioni interne come adde multiply, che accedono alle variabili dichiarate in una funzione esterna ** , sono chiamate chiusure .

Questo è praticamente tutto ciò che c'è da chiudere.


* Ad esempio, copre tutti i punti nell'articolo "Chiusure for Dummies" fornito in un'altra risposta , eccetto l'esempio 6, che mostra semplicemente che le variabili possono essere utilizzate prima di essere dichiarate, un fatto piacevole da conoscere ma completamente estraneo alle chiusure. Copre anche tutti i punti nella risposta accettata , ad eccezione dei punti (1) che le funzioni copiano i loro argomenti in variabili locali (gli argomenti della funzione con nome), e (2) che i numeri di copia creano un nuovo numero, ma copiando un riferimento oggetto ti dà un altro riferimento allo stesso oggetto. Questi sono anche buoni da sapere ma ancora completamente estranei alle chiusure. È anche molto simile all'esempio di questa risposta, ma un po 'più breve e meno astratto. Non copre il punto diquesta risposta o questo commento , ovvero che JavaScript rende difficile collegare la correntevalore di una variabile di ciclo nella tua funzione interna: il passaggio "plug-in" può essere fatto solo con una funzione di aiuto che racchiude la tua funzione interna e viene invocata su ogni iterazione del ciclo. (In senso stretto, la funzione interna accede alla copia della variabile della funzione di aiuto, piuttosto che avere qualcosa collegato.) Ancora una volta, molto utile quando si creano chiusure, ma non fa parte di cosa sia una chiusura o come funzioni. Vi è ulteriore confusione dovuta alle chiusure che funzionano in modo diverso nei linguaggi funzionali come ML, dove le variabili sono legate ai valori piuttosto che allo spazio di archiviazione, fornendo un flusso costante di persone che comprendono le chiusure in un modo (cioè il modo "plug-in") che è semplicemente errato per JavaScript, dove le variabili sono sempre legate allo spazio di archiviazione e mai ai valori.

** Qualsiasi funzione esterna, se più nodi sono nidificati o anche nel contesto globale, come indica chiaramente questa risposta .


Ogni volta che vedi la parola chiave function all'interno di un'altra funzione, la funzione inner ha accesso alle variabili nella funzione esterna.

function foo(x) {
  var tmp = 3;

  function bar(y) {
    console.log(x + y + (++tmp)); // will log 16
  }

  bar(10);
}

foo(2);

Questo logarà sempre 16, perché la bar può accedere alla x che è stata definita come un argomento a foo , e può anche accedere a tmp da foo .

Questa è una chiusura. Una funzione non deve tornare per essere chiamata una chiusura. Semplicemente l'accesso a variabili esterne all'ambito lessicale immediato crea una chiusura .

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + (++tmp)); // will also log 16
  }
}

var bar = foo(2); // bar is now a closure.
bar(10);

La funzione precedente registrerà anche 16, perché la bar può ancora fare riferimento a x e tmp , anche se non è più direttamente all'interno dell'ambito.

Tuttavia, poiché tmp è ancora in agguato all'interno della chiusura della bar , viene anche incrementato. Sarà incrementato ogni volta che chiami bar .

L'esempio più semplice di chiusura è questo:

var a = 10;

function test() {
  console.log(a); // will output 10
  console.log(b); // will output 6
}
var b = 6;
test();

Quando viene invocata una funzione JavaScript, viene creato un nuovo contesto di esecuzione. Insieme agli argomenti della funzione e all'oggetto padre, questo contesto di esecuzione riceve anche tutte le variabili dichiarate al di fuori di esso (nell'esempio precedente, sia 'a' che 'b').

È possibile creare più di una funzione di chiusura, restituendone una lista o impostandole su variabili globali. Tutti questi si riferiscono alla stessa x e allo stesso tmp , non fanno le proprie copie.

Qui il numero x è un numero letterale. Come con altri letterali in JavaScript, quando viene chiamato foo , il numero x viene copiato in foo come argomento x .

D'altra parte, JavaScript usa sempre riferimenti quando si tratta di oggetti. Se dici, hai chiamato foo con un oggetto, la chiusura restituita farà riferimento a quell'oggetto originale!

function foo(x) {
  var tmp = 3;

  return function (y) {
    console.log(x + y + tmp);
    x.memb = x.memb ? x.memb + 1 : 1;
    console.log(x.memb);
  }
}

var age = new Number(2);
var bar = foo(age); // bar is now a closure referencing age.
bar(10);

Come previsto, ogni chiamata a bar(10) incrementerà x.memb . Ciò che potrebbe non essere previsto, è che x si riferisce semplicemente allo stesso oggetto della variabile di age ! Dopo un paio di chiamate al bar , age.memb sarà 2! Questo riferimento è la base per perdite di memoria con oggetti HTML.


PREFAZIONE: questa risposta è stata scritta quando la domanda era:

Come il vecchio Albert ha detto: "Se non riesci a spiegarlo a un bambino di sei anni, davvero non lo capisci da solo." Beh, ho cercato di spiegare le chiusure di JS a un amico di 27 anni e ho completamente fallito.

Qualcuno può considerare che io abbia 6 anni e sia stranamente interessato a quell'argomento?

Sono abbastanza sicuro di essere stato una delle poche persone che ha tentato di rispondere alla domanda iniziale letteralmente. Da allora, la domanda è mutata più volte, quindi la mia risposta potrebbe sembrare incredibilmente stupida e fuori luogo. Speriamo che l'idea generale della storia rimanga divertente per alcuni.

Sono un grande fan dell'analogia e della metafora quando spieghiamo concetti difficili, quindi lasciami provare la mia mano con una storia.

C'era una volta:

C'era una principessa ...

function princess() {

Ha vissuto in un mondo meraviglioso pieno di avventure. Incontrò il suo Principe Azzurro, cavalcò il suo mondo su un unicorno, combatté draghi, incontrò animali parlanti e molte altre cose fantastiche.

    var adventures = [];

    function princeCharming() { /* ... */ }

    var unicorn = { /* ... */ },
        dragons = [ /* ... */ ],
        squirrel = "Hello!";

    /* ... */

Ma avrebbe sempre dovuto tornare al suo noioso mondo di faccende e adulti.

    return {

E lei raccontava spesso la sua ultima incredibile avventura come principessa.

        story: function() {
            return adventures[adventures.length - 1];
        }
    };
}

Ma tutto quello che vedrebbero è una bambina ...

var littleGirl = princess();

... raccontando storie di magia e fantasia.

littleGirl.story();

E anche se i grandi conoscevano le vere principesse, non avrebbero mai creduto negli unicorni o nei draghi perché non potevano mai vederli. Gli adulti dicevano che esistevano solo nell'immaginazione della bambina.

Ma noi conosciamo la vera verità; che la bambina con la principessa dentro ...

... è davvero una principessa con una bambina dentro.


Questo è un tentativo di chiarire alcuni (possibili) equivoci sulle chiusure che appaiono in alcune delle altre risposte.

  • Una chiusura non viene creata solo quando si restituisce una funzione interna. Di fatto, la funzione di chiusura non ha bisogno di tornare affatto per poter creare la chiusura.Potresti invece assegnare la tua funzione interiore a una variabile in un ambito esterno o passarla come argomento a un'altra funzione in cui potrebbe essere richiamata immediatamente o in qualsiasi momento successivo. Pertanto, la chiusura della funzione di chiusura viene probabilmente creata non appena viene chiamata la funzione di chiusura poiché ogni funzione interna ha accesso a tale chiusura ogni volta che viene richiamata la funzione interna, prima o dopo il ritorno della funzione di chiusura.
  • Una chiusura non fa riferimento a una copia dei vecchi valori delle variabili nel suo ambito. Le variabili stesse fanno parte della chiusura, quindi il valore visualizzato quando si accede a una di queste variabili è l'ultimo valore al momento dell'accesso. Questo è il motivo per cui le funzioni interne create all'interno di loop possono essere complicate, dato che ognuna ha accesso alle stesse variabili esterne invece di afferrare una copia delle variabili nel momento in cui la funzione viene creata o chiamata.
  • Le "variabili" in una chiusura includono tutte le funzioni con nome dichiarate all'interno della funzione. Includono anche argomenti della funzione. Una chiusura ha anche accesso alle sue variabili di chiusura contenenti, fino allo scopo globale.
  • Le chiusure utilizzano la memoria, ma non causano perdite di memoria dal momento che JavaScript di per sé ripulisce le proprie strutture circolari che non sono referenziate. Le perdite di memoria di Internet Explorer che coinvolgono le chiusure vengono create quando non riesce a disconnettere i valori degli attributi del DOM che fanno riferimento alle chiusure, mantenendo quindi i riferimenti a possibili strutture circolari.

Wikipedia sulle chiusure :

Nell'informatica, una chiusura è una funzione insieme a un ambiente di riferimento per i nomi non locali (variabili libere) di quella funzione.

Tecnicamente, in JavaScript , ogni funzione è una chiusura . Ha sempre accesso a variabili definite nell'ambito circostante.

Poiché la costruzione di definizione di scope in JavaScript è una funzione , non un blocco di codice come in molti altri linguaggi, ciò che di solito intendiamo per chiusura in JavaScript è una funzione che funziona con variabili non locali definite nella funzione circostante già eseguita .

Le chiusure sono spesso utilizzate per creare funzioni con alcuni dati privati ​​nascosti (ma non è sempre il caso).

var db = (function() {
    // Create a hidden object, which will hold the data
    // it's inaccessible from the outside.
    var data = {};

    // Make a function, which will provide some access to the data.
    return function(key, val) {
        if (val === undefined) { return data[key] } // Get
        else { return data[key] = val } // Set
    }
    // We are calling the anonymous surrounding function,
    // returning the above inner function, which is a closure.
})();

db('x')    // -> undefined
db('x', 1) // Set x to 1
db('x')    // -> 1
// It's impossible to access the data object itself.
// We are able to get or set individual it.

ems

L'esempio precedente utilizza una funzione anonima, che è stata eseguita una volta. Ma non deve essere. Può essere chiamato (es. mkdb) Ed eseguito successivamente, generando una funzione di database ogni volta che viene richiamato. Ogni funzione generata avrà il proprio oggetto di database nascosto. Un altro esempio di utilizzo delle chiusure è quando non restituiamo una funzione, ma un oggetto che contiene più funzioni per scopi diversi, ognuna delle quali ha accesso agli stessi dati.


Come lo spiegherei a un bambino di sei anni:

Sai come gli adulti possono possedere una casa e la chiamano casa? Quando una mamma ha un figlio, il bambino non possiede proprio nulla, giusto? Ma i suoi genitori possiedono una casa, quindi ogni volta che qualcuno chiede al bambino "Dov'è la tua casa?", Lui / lei può rispondere "a quella casa!", E indica la casa dei suoi genitori. Una "chiusura" è la capacità del bambino di sempre (anche se all'estero) essere in grado di dire che ha una casa, anche se è proprio il genitore a possedere la casa.


Esempio per il primo punto di dlaliberte:

Una chiusura non viene creata solo quando si restituisce una funzione interna. In effetti, la funzione di chiusura non ha bisogno di tornare affatto. Potresti invece assegnare la tua funzione interiore a una variabile in un ambito esterno o passarla come argomento a un'altra funzione in cui potrebbe essere utilizzata immediatamente. Pertanto, la chiusura della funzione di chiusura probabilmente esiste già nel momento in cui è stata chiamata la funzione di inclusione poiché qualsiasi funzione interna ha accesso ad essa non appena viene chiamata.

var i;
function foo(x) {
    var tmp = 3;
    i = function (y) {
        console.log(x + y + (++tmp));
    }
}
foo(2);
i(3);

Le funzioni JavaScript possono accedere a:

  1. argomenti
  2. Locali (cioè le loro variabili locali e le funzioni locali)
  3. Ambiente, che include:
    • Globali, incluso il DOM
    • qualsiasi cosa nelle funzioni esterne

Se una funzione accede al suo ambiente, la funzione è una chiusura.

Si noti che le funzioni esterne non sono necessarie, anche se offrono vantaggi di cui non discuto qui. Accedendo ai dati nel proprio ambiente, una chiusura mantiene vivi i dati. Nella sottocasi delle funzioni esterne / interne, una funzione esterna può creare dati locali ed eventualmente uscire, e tuttavia, se una o più funzioni interne sopravvivono dopo che la funzione esterna è terminata, la funzione interna (s) mantiene i dati locali della funzione esterna vivo.

Esempio di chiusura che utilizza l'ambiente globale:

Immagina che gli eventi Button Overflow Vote-Up e Vote-Down siano implementati come chiusure, voteUp_click e voteDown_click, che hanno accesso a variabili esterne isVotedUp e isVotedDown, che sono definite globalmente. (Per ragioni di semplicità, mi riferisco ai pulsanti di votazione delle domande di , non alla serie di pulsanti Rispondi voto.)

Quando l'utente fa clic sul pulsante VoteUp, la funzione voteUp_click verifica se isVotedDown == true per determinare se votare o semplicemente annullare un voto basso. La funzione voteUp_click è una chiusura perché sta accedendo al suo ambiente.

var isVotedUp = false;
var isVotedDown = false;

function voteUp_click() {
  if (isVotedUp)
    return;
  else if (isVotedDown)
    SetDownVote(false);
  else
    SetUpVote(true);
}

function voteDown_click() {
  if (isVotedDown)
    return;
  else if (isVotedUp)
    SetUpVote(false);
  else
    SetDownVote(true);
}

function SetUpVote(status) {
  isVotedUp = status;
  // Do some CSS stuff to Vote-Up button
}

function SetDownVote(status) {
  isVotedDown = status;
  // Do some CSS stuff to Vote-Down button
}

Tutte e quattro queste funzioni sono chiusure in quanto tutte accedono al loro ambiente.


Ok, parlando con un bambino di 6 anni, potrei usare le seguenti associazioni.

Immagina: stai giocando con i tuoi fratellini e sorelline in tutta la casa, e ti muovi con i tuoi giocattoli e ne porti alcuni nella stanza di tuo fratello maggiore. Dopo un po 'tuo fratello tornò dalla scuola e andò nella sua stanza, e lui vi rinchiuse, così ora non potevi accedere ai giocattoli lasciati lì in modo diretto. Ma potresti bussare alla porta e chiedere a tuo fratello quei giocattoli. Questo si chiama chiusura del giocattolo ; tuo fratello ha inventato per te, e ora è nel campo di applicazione esterno .

Confrontati con una situazione in cui una porta è stata bloccata da una brutta copia e nessuno all'interno (esecuzione di una funzione generale), poi un incendio locale si è verificato e ha bruciato la stanza (garbage collector: D), e poi una nuova stanza è stata costruita e ora puoi andartene un altro giocattolo (nuova istanza di funzione), ma mai gli stessi giocattoli che sono stati lasciati nella prima istanza della stanza.

Per un bambino avanzato vorrei mettere qualcosa come il seguente. Non è perfetto, ma ti fa sentire quello che è:

function playingInBrothersRoom (withToys) {
  // We closure toys which we played in the brother's room. When he come back and lock the door
  // your brother is supposed to be into the outer [[scope]] object now. Thanks god you could communicate with him.
  var closureToys = withToys || [],
      returnToy, countIt, toy; // Just another closure helpers, for brother's inner use.

  var brotherGivesToyBack = function (toy) {
    // New request. There is not yet closureToys on brother's hand yet. Give him a time.
    returnToy = null;
    if (toy && closureToys.length > 0) { // If we ask for a specific toy, the brother is going to search for it.

      for ( countIt = closureToys.length; countIt; countIt--) {
        if (closureToys[countIt - 1] == toy) {
          returnToy = 'Take your ' + closureToys.splice(countIt - 1, 1) + ', little boy!';
          break;
        }
      }
      returnToy = returnToy || 'Hey, I could not find any ' + toy + ' here. Look for it in another room.';
    }
    else if (closureToys.length > 0) { // Otherwise, just give back everything he has in the room.
      returnToy = 'Behold! ' + closureToys.join(', ') + '.';
      closureToys = [];
    }
    else {
      returnToy = 'Hey, lil shrimp, I gave you everything!';
    }
    console.log(returnToy);
  }
  return brotherGivesToyBack;
}
// You are playing in the house, including the brother's room.
var toys = ['teddybear', 'car', 'jumpingrope'],
    askBrotherForClosuredToy = playingInBrothersRoom(toys);

// The door is locked, and the brother came from the school. You could not cheat and take it out directly.
console.log(askBrotherForClosuredToy.closureToys); // Undefined

// But you could ask your brother politely, to give it back.
askBrotherForClosuredToy('teddybear'); // Hooray, here it is, teddybear
askBrotherForClosuredToy('ball'); // The brother would not be able to find it.
askBrotherForClosuredToy(); // The brother gives you all the rest
askBrotherForClosuredToy(); // Nothing left in there

Come puoi vedere, i giocattoli lasciati nella stanza sono ancora accessibili tramite il fratello e non importa se la stanza è chiusa. Ecco un jsbin per giocarci.


Una risposta per un bambino di sei anni (ammesso che sappia cos'è una funzione e che cos'è una variabile e quali sono i dati):

Le funzioni possono restituire dati. Un tipo di dati che è possibile restituire da una funzione è un'altra funzione. Quando viene restituita la nuova funzione, tutte le variabili e gli argomenti utilizzati nella funzione che lo ha creato non scompaiono. Invece, quella funzione genitore "si chiude". In altre parole, nulla può guardare al suo interno e vedere le variabili utilizzate tranne la funzione restituita. Quella nuova funzione ha una capacità speciale di guardare indietro all'interno della funzione che lo ha creato e vedere i dati al suo interno.

function the_closure() {
  var x = 4;
  return function () {
    return x; // Here, we look back inside the_closure for the value of x
  }
}

var myFn = the_closure();
myFn(); //=> 4

Un altro modo molto semplice per spiegarlo è in termini di ambito:

Ogni volta che crei un ambito più piccolo all'interno di un ambito più ampio, l'ambito più piccolo sarà sempre in grado di vedere ciò che è nello scope più grande.


Come padre di un bambino di 6 anni, attualmente insegnando ai bambini piccoli (e un parente inesperto alla codifica senza istruzione formale, saranno necessarie correzioni), penso che la lezione si attenga meglio attraverso il gioco pratico. Se il bambino di 6 anni è pronto a capire che cos'è una chiusura, allora è abbastanza grande per andare da solo. Suggerirei di incollare il codice in jsfiddle.net, spiegandone un po 'e lasciandoli da soli a inventare una canzone unica. Il testo esplicativo di seguito è probabilmente più appropriato per un bambino di 10 anni.

function sing(person) {

    var firstPart = "There was " + person + " who swallowed ";

    var fly = function() {
        var creature = "a fly";
        var result = "Perhaps she'll die";
        alert(firstPart + creature + "\n" + result);
    };

    var spider = function() {
        var creature = "a spider";
        var result = "that wiggled and jiggled and tickled inside her";
        alert(firstPart + creature + "\n" + result);
    };

    var bird = function() {
        var creature = "a bird";
        var result = "How absurd!";
        alert(firstPart + creature + "\n" + result);
    };

    var cat = function() {
        var creature = "a cat";
        var result = "Imagine That!";
        alert(firstPart + creature + "\n" + result);
    };

    fly();
    spider();
    bird();
    cat();
}

var person="an old lady";

sing(person);

ISTRUZIONI

DATI: i dati sono una raccolta di fatti. Può essere numeri, parole, misure, osservazioni o anche solo descrizioni di cose. Non puoi toccarlo, annusarlo o assaggiarlo. Puoi scriverlo, parlarlo e ascoltarlo. Potresti usarlo per creare l' odore e il sapore del tocco usando un computer. Può essere reso utile da un computer usando il codice.

CODICE: tutta la scrittura sopra è chiamata codice . È scritto in JavaScript.

JAVASCRIPT: JavaScript è una lingua. Come l'inglese o il francese o il cinese sono le lingue. Esistono molte lingue comprese dai computer e da altri processori elettronici. Perché JavaScript sia compreso da un computer ha bisogno di un interprete. Immagina se un insegnante che parla solo russo venga ad insegnare la tua classe a scuola. Quando l'insegnante dice "все садятся", la classe non capirebbe. Ma per fortuna hai un alunno russo nella tua classe che dice a tutti che questo significa "tutti si siedono" - così tutti voi. La classe è come un computer e l'allievo russo è l'interprete. Per JavaScript l'interprete più comune è chiamato browser.

BROWSER: quando ti connetti a Internet su un computer, tablet o telefono per visitare un sito web, utilizzi un browser. Esempi che potresti conoscere sono Internet Explorer, Chrome, Firefox e Safari. Il browser può capire JavaScript e dire al computer cosa deve fare. Le istruzioni JavaScript sono chiamate funzioni.

FUNZIONE: una funzione in JavaScript è come una fabbrica. Potrebbe essere una piccola fabbrica con una sola macchina al suo interno. Oppure potrebbe contenere molte altre piccole fabbriche, ognuna con molte macchine che svolgono diversi lavori. In una vera e propria fabbrica di vestiti per la vita potresti avere delle risme di stoffa e di fili di filo infilati e t-shirt e jeans che escono. La nostra fabbrica JavaScript elabora solo i dati, non può cucire, praticare un foro o fondere il metallo. Nei nostri dati di fabbrica JavaScript entra e i dati vengono fuori.

Tutta questa roba di dati sembra un po 'noiosa, ma è davvero molto interessante; potremmo avere una funzione che dice a un robot cosa preparare per cena. Diciamo che invito te e il tuo amico a casa mia. Ti piacciono le cosce di pollo, mi piacciono le salsicce, il tuo amico vuole sempre quello che vuoi e il mio amico non mangia carne.

Non ho tempo per fare shopping, quindi la funzione deve sapere cosa abbiamo in frigo per prendere decisioni. Ogni ingrediente ha un tempo di cottura diverso e vogliamo che tutto sia servito caldo dal robot allo stesso tempo. Abbiamo bisogno di fornire la funzione con i dati su ciò che ci piace, la funzione potrebbe 'parlare' al frigorifero e la funzione potrebbe controllare il robot.

Normalmente una funzione ha un nome, parentesi e parentesi graffe. Come questo:

function cookMeal() {  /*  STUFF INSIDE THE FUNCTION  */  }

Si noti che /*...*/e il //codice di arresto viene letto dal browser.

NOME: puoi chiamare una funzione qualunque sia la parola che vuoi. L'esempio "cookMeal" è tipico nell'unire due parole insieme e dare alla seconda una lettera maiuscola all'inizio, ma questo non è necessario. Non può contenere uno spazio e non può essere un numero a sé stante.

PARENTHESES: "Parentesi" o ()casella postale sulla porta della factory di funzioni JavaScript o casella postale in strada per l'invio di pacchetti di informazioni alla fabbrica. A volte la casella postale potrebbe essere contrassegnata per esempio cookMeal(you, me, yourFriend, myFriend, fridge, dinnerTime) , nel qual caso si sa quali dati si devono dare.

BRETELLE: "Bretelle" che assomigliano a questo {}sono le finestre colorate della nostra fabbrica. Dall'interno della fabbrica puoi vedere, ma dall'esterno non puoi vedere.

L'ESEMPIO DI CODICE LUNGO SOPRA

Il nostro codice inizia con la funzione parola , quindi sappiamo che è uno! Quindi il nome della funzione sing - questa è la mia descrizione di cosa tratta la funzione. Quindi parentesi () . Le parentesi sono sempre lì per una funzione. A volte sono vuoti, e, talvolta, hanno qualcosa in questo si ha una parola in.: (person). Dopo questo c'è un tutore come questo {. Questo segna l'inizio della funzione sing () . Ha un partner che segna la fine di cantare () come questo}

function sing(person) {  /* STUFF INSIDE THE FUNCTION */  }

Quindi questa funzione potrebbe avere qualcosa a che fare con il canto e potrebbe aver bisogno di alcuni dati su una persona. Ha delle istruzioni dentro per fare qualcosa con quei dati.

Ora, dopo la funzione sing () , vicino alla fine del codice c'è la linea

var person="an old lady";

VARIABILE: le lettere var indicano "variabile". Una variabile è come una busta. All'esterno questa busta è contrassegnata come "persona". All'interno contiene un foglietto di carta con le informazioni di cui la nostra funzione ha bisogno, alcune lettere e spazi uniti come un pezzo di corda (si chiama una stringa) che fa una frase che legge "una vecchia signora". La nostra busta potrebbe contenere altri tipi di cose come numeri (chiamati interi), istruzioni (chiamate funzioni), elenchi (chiamati array ). Poiché questa variabile è scritta al di fuori di tutte le parentesi graffe {}e poiché è possibile vedere attraverso le finestre colorate quando ci si trova all'interno delle parentesi graffe, questa variabile può essere vista da qualsiasi parte del codice. La chiamiamo una "variabile globale".

VARIABILE GLOBALE: la persona è una variabile globale, il che significa che se cambi il suo valore da "una vecchia signora" a "un giovane uomo", la persona continuerà ad essere un giovane finché non deciderai di cambiarla di nuovo e qualsiasi altra funzione in il codice può vedere che è un giovane uomo. Premi il F12pulsante o guarda le impostazioni di Opzioni per aprire la console di sviluppo di un browser e digitare "persona" per vedere qual è questo valore. Digita person="a young man"per cambiarlo e quindi digita "person" di nuovo per vedere che è cambiato.

Dopo questo abbiamo la linea

sing(person);

Questa linea chiama la funzione, come se stesse chiamando un cane

"Vieni a cantare , vieni a prendere la persona !"

Quando il browser ha caricato il codice JavaScript e ha raggiunto questa linea, avvierà la funzione. Metto la linea alla fine per assicurarmi che il browser abbia tutte le informazioni necessarie per eseguirlo.

Le funzioni definiscono le azioni - la funzione principale riguarda il canto. Contiene una variabile chiamata firstPart che si applica al canto della persona che si applica a ciascuno dei versi della canzone: "C'era" + persona + "che inghiottì". Se si digita firstPart nella console, non si otterrà una risposta perché la variabile è bloccata in una funzione - il browser non può vedere all'interno delle finestre colorate delle parentesi graffe.

CHIUSURE: le chiusure sono le funzioni più piccole che si trovano all'interno della funzione big sing () . Le piccole fabbriche all'interno della grande fabbrica. Ognuno di loro ha le proprie parentesi, il che significa che le variabili al loro interno non possono essere viste dall'esterno. Ecco perché i nomi delle variabili ( creatura e risultato ) possono essere ripetuti nelle chiusure ma con valori diversi. Se digiti questi nomi di variabili nella finestra della console, non otterrai il suo valore perché è nascosto da due livelli di finestre colorate.

Le chiusure sanno tutte quale sia la variabile della funzione sing () chiamata firstPart , perché possono vedere dalle loro finestre colorate.

Dopo le chiusure arrivano le linee

fly();
spider();
bird();
cat();

La funzione sing () chiamerà ognuna di queste funzioni nell'ordine in cui vengono fornite. Quindi il lavoro della funzione sing () verrà eseguito.


Ho scritto un post sul blog un po 'indietro spiegando chiusure. Ecco cosa ho detto sulle chiusure in termini di perché ne vorrai una.

Le chiusure sono un modo per consentire a una funzione di avere variabili permanenti, private , ovvero variabili di cui solo una funzione è a conoscenza, in cui può tenere traccia delle informazioni delle precedenti volte in cui è stata eseguita.

In questo senso, lasciano che una funzione agisca un po 'come un oggetto con attributi privati.

Post completo:

Quindi quali sono questi thingys di chiusura?


L'autore di Closures ha spiegato le chiusure abbastanza bene, spiegando il motivo per cui abbiamo bisogno di loro e spiegando anche LexicalEnvironment, che è necessario per capire chiusure.
Ecco il riassunto:

Cosa succede se si accede a una variabile, ma non è locale? Come qui:

In questo caso, l'interprete trova la variabile LexicalEnvironmentnell'oggetto esterno .

Il processo si compone di due passaggi:

  1. Innanzitutto, quando viene creata una funzione f, non viene creata in uno spazio vuoto. C'è un oggetto LexicalEnvironment corrente. Nel caso precedente, è finestra (a non è definita al momento della creazione della funzione).

Quando viene creata una funzione, ottiene una proprietà nascosta, denominata [[Ambito]], che fa riferimento all'attuale ambiente Lexical.

Se una variabile viene letta, ma non può essere trovata da nessuna parte, viene generato un errore.

Funzioni annidate

Le funzioni possono essere annidate l'una dentro l'altra, formando una catena di ambienti Lexical che può anche essere definita una catena di portata.

Quindi, la funzione g ha accesso a g, ae f.

chiusure

Una funzione nidificata può continuare a vivere dopo che la funzione esterna ha terminato:

Marcatura di ambienti Lexical:

Come si vede, this.sayè una proprietà nell'oggetto utente, quindi continua a vivere dopo aver completato l'utente.

E se ricordi, quando this.sayviene creato, esso (come ogni funzione) ottiene un riferimento interno this.say.[[Scope]]all'attuale ambiente Lexical. Quindi, il LexicalEnvironment dell'esecuzione corrente dell'utente rimane in memoria. Tutte le variabili dell'utente sono anche le sue proprietà, quindi sono anche tenute con cura, non annullate come di consueto.

Il punto è assicurarsi che se la funzione interiore vuole accedere a una variabile esterna in futuro, è in grado di farlo.

Riassumere:

  1. La funzione interna mantiene un riferimento al LexicalEnvironment esterno.
  2. La funzione interna può accedere a variabili da esso in qualsiasi momento anche se la funzione esterna è finita.
  3. Il browser mantiene in memoria il LexicalEnvironment e tutte le sue proprietà (variabili) finché non vi è una funzione interna che la fa riferimento.

Questo è chiamato una chiusura.


OK, fan delle chiusure di 6 anni. Vuoi sentire l'esempio più semplice di chiusura?

Immaginiamo la prossima situazione: un autista è seduto in una macchina. Quella macchina è dentro un aereo. L'aereo è in aeroporto. La capacità del guidatore di accedere a cose al di fuori della sua auto, ma all'interno dell'aereo, anche se quell'aereo lascia un aeroporto, è una chiusura. Questo è tutto.Quando compi il 27, guarda la spiegazione più dettagliata o nell'esempio qui sotto.

Ecco come posso convertire la mia storia piana nel codice.

var plane = function(defaultAirport) {

  var lastAirportLeft = defaultAirport;

  var car = {
    driver: {
      startAccessPlaneInfo: function() {
        setInterval(function() {
          console.log("Last airport was " + lastAirportLeft);
        }, 2000);
      }
    }
  };
  car.driver.startAccessPlaneInfo();

  return {
    leaveTheAirport: function(airPortName) {
      lastAirportLeft = airPortName;
    }
  }
}("Boryspil International Airport");

plane.leaveTheAirport("John F. Kennedy");


Stai dormendo e inviti Dan. Dì a Dan di portare un controller XBox.

Dan invita Paul. Dan chiede a Paul di portare un controller. Quanti controllori sono stati portati alla festa?

function sleepOver(howManyControllersToBring) {

    var numberOfDansControllers = howManyControllersToBring;

    return function danInvitedPaul(numberOfPaulsControllers) {
        var totalControllers = numberOfDansControllers + numberOfPaulsControllers;
        return totalControllers;
    }
}

var howManyControllersToBring = 1;

var inviteDan = sleepOver(howManyControllersToBring);

// The only reason Paul was invited is because Dan was invited. 
// So we set Paul's invitation = Dan's invitation.

var danInvitedPaul = inviteDan(howManyControllersToBring);

alert("There were " + danInvitedPaul + " controllers brought to the party.");

Una chiusura è molto simile a un oggetto. Viene istanziato ogni volta che si chiama una funzione.

Lo scopo di una chiusura in JavaScript è lessicale, il che significa che tutto ciò che è contenuto nella funzione a cui appartiene la chiusura , ha accesso a qualsiasi variabile che è in essa.

Una variabile è contenuta nella chiusura se tu

  1. assegnarlo con var foo=1; o
  2. Scrivi e basta var foo;

Se una funzione interna (una funzione contenuta in un'altra funzione) accede a tale variabile senza definirla nel suo ambito con var, modifica il contenuto della variabile nella chiusura esterna .

Una chiusura sopravvive al runtime della funzione che lo ha generato. Se altre funzioni escono dalla chiusura / ambito in cui sono definite (ad esempio come valori di ritorno), quelle continueranno a fare riferimento a tale chiusura .

Esempio

function example(closure) {
  // define somevariable to live in the closure of example
  var somevariable = 'unchanged';

  return {
    change_to: function(value) {
      somevariable = value;
    },
    log: function(value) {
      console.log('somevariable of closure %s is: %s',
        closure, somevariable);
    }
  }
}

closure_one = example('one');
closure_two = example('two');

closure_one.log();
closure_two.log();
closure_one.change_to('some new value');
closure_one.log();
closure_two.log();

Produzione

somevariable of closure one is: unchanged
somevariable of closure two is: unchanged
somevariable of closure one is: some new value
somevariable of closure two is: unchanged

Una chiusura è dove una funzione interna ha accesso alle variabili nella sua funzione esterna. Questa è probabilmente la più semplice spiegazione a una linea che puoi ottenere per chiusure.







closures