Domanda

Ho posto una domanda sul currying e sono state menzionate le chiusure.Cos'è una chiusura?Che rapporto ha con il curry?

È stato utile?

Soluzione

Ambito variabile

Quando dichiari una variabile locale, quella variabile ha un ambito.Generalmente, le variabili locali esistono solo all'interno del blocco o della funzione in cui le dichiari.

function() {
  var a = 1;
  console.log(a); // works
}    
console.log(a); // fails

Se provo ad accedere a una variabile locale, la maggior parte delle lingue la cercherà nell'ambito corrente, quindi attraverso gli ambiti principali fino a raggiungere l'ambito radice.

var a = 1;
function() {
  console.log(a); // works
}    
console.log(a); // works

Una volta terminato un blocco o una funzione, le sue variabili locali non sono più necessarie e di solito vengono esaurite dalla memoria.

Questo è il modo in cui normalmente ci aspettiamo che le cose funzionino.

Una chiusura è un ambito di variabile locale persistente

Una chiusura è un ambito persistente che mantiene le variabili locali anche dopo che l'esecuzione del codice è uscita da quel blocco.I linguaggi che supportano la chiusura (come JavaScript, Swift e Ruby) ti permetteranno di mantenere un riferimento a un ambito (inclusi i suoi ambiti principali), anche dopo che il blocco in cui sono state dichiarate tali variabili ha terminato l'esecuzione, a condizione che tu mantenga un riferimento a quel blocco o funzione da qualche parte.

L'oggetto ambito e tutte le sue variabili locali sono legati alla funzione e persisteranno finché persiste tale funzione.

Questo ci dà la portabilità delle funzioni.Possiamo aspettarci che tutte le variabili che erano nell'ambito quando la funzione è stata definita per la prima volta siano ancora nell'ambito quando successivamente chiameremo la funzione, anche se chiamiamo la funzione in un contesto completamente diverso.

Per esempio

Ecco un esempio davvero semplice in JavaScript che illustra il punto:

outer = function() {
  var a = 1;
  var inner = function() {
    console.log(a);
  }
  return inner; // this returns a function
}

var fnc = outer(); // execute outer to get inner 
fnc();

Qui ho definito una funzione all'interno di una funzione.La funzione interna ottiene l'accesso a tutte le variabili locali della funzione esterna, incluso a.La variabile a rientra nell'ambito della funzione interna.

Normalmente quando una funzione esce, tutte le sue variabili locali vengono spazzate via.Tuttavia, se restituiamo la funzione interna e la assegniamo a una variabile fnc in modo che persista dopo outer è uscito, tutte le variabili che erano nell'ambito quando inner è stato definito anche persistere.La variabile a è stato chiuso: è all'interno di una chiusura.

Tieni presente che la variabile a è totalmente privato fnc.Questo è un modo per creare variabili private in un linguaggio di programmazione funzionale come JavaScript.

Come potresti immaginare, quando chiamo fnc() stampa il valore di a, che è "1".

In un linguaggio senza chiusura, la variabile a sarebbe stata raccolta spazzatura e gettata via quando la funzione outer uscito.Chiamare fnc avrebbe generato un errore perché a non esiste più.

In JavaScript, la variabile a persiste perché l'ambito della variabile viene creato quando la funzione viene dichiarata per la prima volta e persiste finché la funzione continua ad esistere.

a appartiene all'ambito di outer.Lo scopo di inner ha un puntatore genitore all'ambito di outer. fnc è una variabile che punta a inner. a persiste finché fnc persiste. a è entro la chiusura.

Altri suggerimenti

Darò un esempio (in JavaScript):

function makeCounter () {
  var count = 0;
  return function () {
    count += 1;
    return count;
  }
}

var x = makeCounter();

x(); returns 1

x(); returns 2

...etc...

Ciò che fa questa funzione, makeCounter, è restituire una funzione, che abbiamo chiamato x, che conterà di uno ogni volta che viene chiamata.Dato che non stiamo fornendo alcun parametro a x, deve in qualche modo ricordare il conteggio.Sa dove trovarlo in base a quello che viene chiamato scoping lessicale: deve guardare nel punto in cui è definito per trovare il valore.Questo valore "nascosto" è ciò che viene chiamato chiusura.

Ecco di nuovo il mio esempio di currying:

function add (a) {
  return function (b) {
    return a + b;
  }
}

var add3 = add(3);

add3(4); returns 7

Quello che puoi vedere è che quando chiami add con il parametro a (che è 3), quel valore è contenuto nella chiusura della funzione restituita che stiamo definendo come add3.In questo modo, quando chiamiamo add3 sa dove trovare il valore a per eseguire l'addizione.

La risposta di Kyle è abbastanza buonoPenso che l'unico chiarimento aggiuntivo sia che la chiusura è fondamentalmente un'istantanea dello stack nel punto in cui viene creata la funzione lambda.Quindi, quando la funzione viene rieseguita, lo stack viene ripristinato allo stato precedente all'esecuzione della funzione.Quindi, come menziona Kyle, quel valore nascosto (count) è disponibile quando viene eseguita la funzione lambda.

Innanzitutto, contrariamente a quanto vi dice la maggior parte delle persone qui, la chiusura è non una funzione!E allora È Esso?
È un impostato di simboli definiti nel "contesto circostante" di una funzione (noto come its ambiente) che la rendono un'espressione CHIUSA (ovvero un'espressione in cui ogni simbolo è definito e ha un valore, quindi può essere valutato).

Ad esempio, quando hai una funzione JavaScript:

function closed(x) {
  return x + 3;
}

è un espressione chiusa perché tutti i simboli che vi compaiono sono definiti in esso (i loro significati sono chiari), quindi puoi valutarlo.In altre parole, lo è autonomo.

Ma se hai una funzione come questa:

function open(x) {
  return x*y + 3;
}

è un espressione aperta perché in esso ci sono dei simboli che non sono stati definiti.Vale a dire, y.Osservando questa funzione, non possiamo dire cosa y is e cosa significa, non ne conosciamo il valore, quindi non possiamo valutare questa espressione.Cioè.non possiamo chiamare questa funzione finché non diciamo cosa y dovrebbe significare in esso.Questo y si chiama a variabile libera.

Questo y richiede una definizione, ma questa definizione non è parte della funzione – è definita da qualche altra parte, nel suo "contesto circostante" (noto anche come ambiente).Almeno questo è quello che speriamo :P

Ad esempio, potrebbe essere definito globalmente:

var y = 7;

function open(x) {
  return x*y + 3;
}

Oppure potrebbe essere definito in una funzione che lo avvolge:

var global = 2;

function wrapper(y) {
   var w = "unused";

   return function(x) {
     return x*y + 3;
   }

}

La parte dell'ambiente che conferisce il significato alle variabili libere di un'espressione è il chiusura.Si chiama così perché gira un aprire espressione in a Chiuso uno, fornendo queste definizioni mancanti per tutti i suoi variabili libere, in modo da poterlo valutare.

Nell'esempio sopra, la funzione interna (a cui non abbiamo dato un nome perché non ne avevamo bisogno) è an espressione aperta perché la variabile y in esso è gratuito – la sua definizione è fuori dalla funzione, nella funzione che lo avvolge.IL ambiente per quella funzione anonima è l'insieme di variabili:

{
  global: 2,
  w: "unused",
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

Ora il chiusura è quella parte di questo ambiente che chiude la funzione interna fornendo le definizioni per tutte le sue variabili libere.Nel nostro caso, l'unica variabile libera nella funzione interna era y, quindi la chiusura di quella funzione è questo sottoinsieme del suo ambiente:

{
  y: [whatever has been passed to that wrapper function as its parameter `y`]
}

Gli altri due simboli definiti nell'ambiente sono non parte di chiusura di quella funzione, perché non ne richiede l'esecuzione.Non ce n'è bisogno vicino Esso.

Maggiori informazioni sulla teoria alla base di ciò qui:https://stackoverflow.com/a/36878651/434562

Vale la pena notare che nell'esempio sopra, la funzione wrapper restituisce la sua funzione interna come valore.Il momento in cui chiamiamo questa funzione può essere remoto nel tempo dal momento in cui la funzione è stata definita (o creata).In particolare, la sua funzione di wrap non è più in esecuzione e i suoi parametri che erano nello stack di chiamate non ci sono più: P Questo crea un problema, perché la funzione interna necessita y essere lì quando verrà chiamato!In altre parole, richiede delle variabili dalla sua chiusura fino in qualche modo sopravvivere la funzione wrapper ed essere presente quando necessario.Pertanto, la funzione interna deve fare a istantanea di queste variabili che ne effettuano la chiusura e le memorizzano in un posto sicuro per un uso successivo.(Da qualche parte fuori dallo stack di chiamate.)

Ed è per questo che spesso le persone confondono il termine chiusura per essere quel tipo speciale di funzione che può eseguire tali istantanee delle variabili esterne che utilizzano o della struttura dati utilizzata per memorizzare queste variabili per dopo.Ma spero che tu capisca ora che lo sono non la chiusura stessa: sono solo modi per farlo strumento chiusure in un linguaggio di programmazione o meccanismi linguistici che consentono alle variabili della chiusura della funzione di essere presenti quando necessario.Ci sono molte idee sbagliate sulle chiusure che (inutilmente) rendono questo argomento molto più confuso e complicato di quanto non sia in realtà.

Una chiusura è una funzione che può fare riferimento allo stato in un'altra funzione.Ad esempio, in Python, viene utilizzata la chiusura "inner":

def outer (a):
    b = "variable in outer()"
    def inner (c):
        print a, b, c
    return inner

# Now the return value from outer() can be saved for later
func = outer ("test")
func (1) # prints "test variable in outer() 1

Per facilitare la comprensione delle chiusure potrebbe essere utile esaminare come potrebbero essere implementate in un linguaggio procedurale.Questa spiegazione seguirà un'implementazione semplicistica delle chiusure nello Schema.

Per iniziare, devo introdurre il concetto di namespace.Quando inserisci un comando in un interprete Scheme, deve valutare i vari simboli nell'espressione e ottenere il loro valore.Esempio:

(define x 3)

(define y 4)

(+ x y) returns 7

Le espressioni di definizione memorizzano il valore 3 nello spot per x e il valore 4 nello spot per y.Quindi quando chiamiamo (+ x y), l'interprete cerca i valori nello spazio dei nomi ed è in grado di eseguire l'operazione e restituire 7.

Tuttavia, in Scheme sono presenti espressioni che consentono di sovrascrivere temporaneamente il valore di un simbolo.Ecco un esempio:

(define x 3)

(define y 4)

(let ((x 5))
   (+ x y)) returns 9

x returns 3

Ciò che fa la parola chiave let è introdurre un nuovo spazio dei nomi con x come valore 5.Noterai che è ancora in grado di vedere che y è 4, facendo sì che la somma restituita sia 9.Puoi anche vedere che una volta terminata l'espressione x torna ad essere 3.In questo senso x è stato temporaneamente mascherato dal valore locale.

I linguaggi procedurali e orientati agli oggetti hanno un concetto simile.Ogni volta che dichiari una variabile in una funzione che ha lo stesso nome di una variabile globale ottieni lo stesso effetto.

Come lo implementeremmo?Un modo semplice è con un elenco collegato: la testa contiene il nuovo valore e la coda contiene il vecchio spazio dei nomi.Quando devi cercare un simbolo, inizi dalla testa e procedi verso la coda.

Passiamo ora all'implementazione delle funzioni di prima classe.Più o meno, una funzione è un insieme di istruzioni da eseguire quando la funzione viene chiamata e culmina nel valore restituito.Quando leggiamo una funzione, possiamo memorizzare queste istruzioni dietro le quinte ed eseguirle quando viene chiamata la funzione.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns ?

Definiamo x come 3 e più-x come il suo parametro, y, più il valore di x.Infine chiamiamo plus-x in un ambiente in cui x è stato mascherato da un nuovo x, questo vale 5.Se memorizziamo semplicemente l'operazione, (+ x y), per la funzione più-x, poiché siamo nel contesto in cui x è 5, il risultato restituito sarebbe 9.Questo è ciò che viene chiamato ambito dinamico.

Tuttavia, Scheme, Common Lisp e molti altri linguaggi hanno quello che viene chiamato scoping lessicale: oltre a memorizzare l'operazione (+ x y) memorizziamo anche lo spazio dei nomi in quel punto particolare.In questo modo, quando guardiamo i valori possiamo vedere che x, in questo contesto, è in realtà 3.Questa è una chiusura.

(define x 3)

(define (plus-x y)
  (+ x y))

(let ((x 5))
  (plus-x 4)) returns 7

In sintesi, possiamo utilizzare un elenco collegato per memorizzare lo stato dello spazio dei nomi al momento della definizione della funzione, permettendoci di accedere alle variabili dagli ambiti che le contengono, oltre a fornirci la possibilità di mascherare localmente una variabile senza influenzare il resto dell'elenco. programma.

Ecco un esempio reale del perché le Closures spaccano...Questo è uscito direttamente dal mio codice Javascript.Lasciami illustrare.

Function.prototype.delay = function(ms /*[, arg...]*/) {
  var fn = this,
      args = Array.prototype.slice.call(arguments, 1);

  return window.setTimeout(function() {
      return fn.apply(fn, args);
  }, ms);
};

Ed ecco come lo useresti:

var startPlayback = function(track) {
  Player.play(track);  
};
startPlayback(someTrack);

Ora immagina di voler avviare la riproduzione in modo ritardato, ad esempio 5 secondi dopo l'esecuzione di questo snippet di codice.Beh, è ​​facile con delay ed è la chiusura:

startPlayback.delay(5000, someTrack);
// Keep going, do other things

Quando chiami delay con 5000ms, il primo frammento viene eseguito e memorizza gli argomenti passati nella sua chiusura.Poi 5 secondi dopo, quando il setTimeout avviene il callback, la chiusura mantiene comunque quelle variabili, quindi può chiamare la funzione originale con i parametri originali.
Questo è un tipo di curry o decorazione funzionale.

Senza chiusure, dovresti in qualche modo mantenere lo stato di quelle variabili all'esterno della funzione, riempiendo così il codice all'esterno della funzione con qualcosa che logicamente appartiene ad essa.L'uso delle chiusure può migliorare notevolmente la qualità e la leggibilità del codice.

tl; dott

Una chiusura è una funzione e il suo ambito assegnato a (o utilizzato come) una variabile.Pertanto, la chiusura del nome:l'ambito e la funzione sono racchiusi e utilizzati proprio come qualsiasi altra entità.

Spiegazione approfondita in stile Wikipedia

Secondo Wikipedia, una chiusura È:

Tecniche per implementare l'associazione di nomi con ambito lessicale in lingue con funzioni di prima classe.

Che cosa significa?Vediamo alcune definizioni.

Spiegherò le chiusure e altre definizioni correlate utilizzando questo esempio:

function startAt(x) {
    return function (y) {
        return x + y;
    }
}

var closure1 = startAt(1);
var closure2 = startAt(5);

console.log(closure1(3)); // 4 (x == 1, y == 3)
console.log(closure2(3)); // 8 (x == 5, y == 3)

Funzioni di prima classe

Fondamentalmente questo significa possiamo usare le funzioni proprio come qualsiasi altra entità.Possiamo modificarli, passarli come argomenti, restituirli da funzioni o assegnarli a variabili.Tecnicamente parlando, lo sono cittadini di prima classe, da qui il nome:funzioni di prima classe.

Nell'esempio sopra, startAt restituisce un (anonimo) funzione a cui viene assegnata la funzione closure1 E closure2.Quindi, come vedi, JavaScript tratta le funzioni proprio come qualsiasi altra entità (cittadini di prima classe).

Nome vincolante

Nome vincolante si tratta di scoprirlo quali dati una variabile (identificatore) Riferimenti.L'ambito è davvero importante in questo caso, poiché è l'elemento che determinerà la modalità di risoluzione di un'associazione.

Nell'esempio sopra:

  • Nell'ambito della funzione anonima interna, y è obbligato a 3.
  • In startAtil suo ambito, x è obbligato a 1 O 5 (a seconda della chiusura).

Nell'ambito della funzione anonima, x non è vincolato ad alcun valore, quindi deve essere risolto in un valore superiore (startAt's) ambito.

Scoping lessicale

COME Wikipedia dice, l'ambito:

È la regione di un programma per computer in cui è valida l'associazione: dove il nome può essere utilizzato per riferirsi all'entità.

Esistono due tecniche:

  • Scoping lessicale (statico):La definizione di una variabile viene risolta cercando il blocco o la funzione che lo contiene, quindi, se fallisce, la ricerca nel blocco contenitore esterno e così via.
  • Ambito dinamico:Viene cercata la funzione chiamante, quindi la funzione che ha chiamato quella funzione chiamante e così via, procedendo verso l'alto nello stack di chiamate.

Per ulteriori spiegazioni, dai un'occhiata a questa domanda E dai un'occhiata a Wikipedia.

Nell'esempio sopra, possiamo vedere che JavaScript ha un ambito lessicale, perché quando x viene risolta, la rilegatura viene cercata nella parte superiore (startAt's), basato sul codice sorgente (la funzione anonima che cerca x è definita all'interno startAt) e non in base allo stack di chiamate, al modo in cui (l'ambito in cui) è stata chiamata la funzione.

Avvolgere (chiudere).

Nel nostro esempio, quando chiamiamo startAt, restituirà una funzione (di prima classe) a cui verrà assegnata closure1 E closure2 quindi viene creata una chiusura, perché le variabili passate 1 E 5 sarà salvato dentro startAt, che verrà racchiuso nella funzione anonima restituita.Quando chiamiamo questa funzione anonima tramite closure1 E closure2 con lo stesso argomento (3), il valore di y verrà trovato immediatamente (poiché questo è il parametro di quella funzione), ma x non è limitato all'ambito della funzione anonima, quindi la risoluzione continua nell'ambito della funzione superiore (lessicamente) (che è stata salvata nella chiusura) dove x risulta essere vincolato a entrambi 1 O 5.Ora sappiamo tutto per la somma quindi il risultato può essere restituito, quindi stampato.

Ora dovresti capire le chiusure e come si comportano, che è una parte fondamentale di JavaScript.

Curry

Oh, e hai anche imparato cosa currying riguarda:usi le funzioni (chiusure) per passare ogni argomento di un'operazione invece di usare una funzione con più parametri.

Le funzioni che non contengono variabili libere sono chiamate funzioni pure.

Le funzioni che contengono una o più variabili libere sono chiamate chiusure.

var pure = function pure(x){
  return x 
  // only own environment is used
}

var foo = "bar"

var closure = function closure(){
  return foo 
  // foo is a free variable from the outer environment
}

origine: https://leanpub.com/javascriptallongesix/read#leanpub-auto-if-functions-without-free-variables-are-pure-are-closures-impure

In una situazione normale, le variabili sono vincolate dalla regola di ambito:Le variabili locali funzionano solo all'interno della funzione definita.La chiusura è un modo per infrangere temporaneamente questa regola per comodità.

def n_times(a_thing)
  return lambda{|n| a_thing * n}
end

nel codice sopra, lambda(|n| a_thing * n} è la chiusura perché a_thing viene indicato da lambda (un creatore di funzioni anonimo).

Ora, se inserisci la funzione anonima risultante in una variabile di funzione.

foo = n_times(4)

foo infrangerà la normale regola di scope e inizierà a utilizzare 4 internamente.

foo.call(3)

restituisce 12.

In breve, il puntatore a funzione è semplicemente un puntatore a una posizione nel codice base del programma (come il contatore del programma).Mentre Chiusura = Puntatore funzione + Stack frame.

.

Chiusura è una funzionalità di JavaScript in cui una funzione ha accesso alle proprie variabili di ambito, accesso alle variabili della funzione esterna e accesso alle variabili globali.

Closure ha accesso all'ambito della funzione esterna anche dopo che la funzione esterna è stata restituita.Ciò significa che una chiusura può ricordare e accedere a variabili e argomenti della sua funzione esterna anche dopo che la funzione è terminata.

La funzione interna può accedere alle variabili definite nel proprio ambito, nell'ambito della funzione esterna e nell'ambito globale.E la funzione esterna può accedere alla variabile definita nel proprio ambito e nell'ambito globale.

******************
Example of Closure
******************

var globalValue = 5;

function functOuter() 
{
    var outerFunctionValue = 10;

    //Inner function has access to the outer function value
    //and the global variables
    function functInner() 
    {
        var innerFunctionValue = 5;
        alert(globalValue+outerFunctionValue + innerFunctionValue);
    }
    functInner();
}
functOuter();

L'output sarà 20 quale somma della variabile propria della funzione interna, della variabile della funzione esterna e del valore della variabile globale.

Ecco un altro esempio di vita reale e l'utilizzo di un linguaggio di scripting popolare nei giochi: Lua.Avevo bisogno di cambiare leggermente il modo in cui funzionava una funzione di libreria per evitare un problema con la mancata disponibilità di stdin.

local old_dofile = dofile

function dofile( filename )
  if filename == nil then
    error( 'Can not use default of stdin.' )
  end

  old_dofile( filename )
end

Il valore di old_dofile scompare quando questo blocco di codice termina il suo ambito (perché è locale), tuttavia il valore è stato racchiuso in una chiusura, quindi la nuova funzione dofile ridefinita PUÒ accedervi, o meglio una copia memorizzata insieme alla funzione come un 'sopravvalutare'.

Da Lua.org:

Quando una funzione viene scritta racchiusa in un'altra funzione, ha pieno accesso alle variabili locali dalla funzione che la racchiude;questa funzionalità è chiamata scoping lessicale.Sebbene ciò possa sembrare ovvio, non lo è.L'ambito lessicale, oltre alle funzioni di prima classe, è un concetto potente in un linguaggio di programmazione, ma pochi linguaggi supportano questo concetto.

Se provieni dal mondo Java, puoi confrontare una chiusura con una funzione membro di una classe.Guarda questo esempio

var f=function(){
  var a=7;
  var g=function(){
    return a;
  }
  return g;
}

La funzione g è una chiusura: g chiude a In.COSÌ g può essere paragonato a una funzione membro, a può essere confrontato con un campo di classe e la funzione f con una classe.

Chiusura ogni volta che abbiamo una funzione definita all'interno di un'altra funzione, la funzione interna ha accesso alle variabili dichiarate nella funzione esterna.Le chiusure sono meglio spiegate con esempi.Nell'elenco 2-18, è possibile vedere che la funzione interna ha accesso a una variabile (variabile infunzione) dall'ambito esterno.Le variabili nella funzione esterna sono state chiuse (o legate) dalla funzione interna.Da qui il termine chiusura.Il concetto in sé è abbastanza semplice e abbastanza intuitivo.

Listing 2-18:
    function outerFunction(arg) {
     var variableInOuterFunction = arg;

     function bar() {
             console.log(variableInOuterFunction); // Access a variable from the outer scope
     }
     // Call the local function to demonstrate that it has access to arg
     bar(); 
    }
    outerFunction('hello closure!'); // logs hello closure!

fonte: http://index-of.es/Varios/Basarat%20Ali%20Syed%20(auth.)-Beginning%20Node.js-Apress%20(2014).pdf

Dai un'occhiata al codice seguente per comprendere la chiusura in modo più approfondito:

        for(var i=0; i< 5; i++){            
            setTimeout(function(){
                console.log(i);
            }, 1000);                        
        }

Ecco cosa verrà prodotto? 0,1,2,3,4 non sarà così 5,5,5,5,5 a causa della chiusura

Allora come risolverà?La risposta è qui sotto:

       for(var i=0; i< 5; i++){
           (function(j){     //using IIFE           
                setTimeout(function(){
                               console.log(j);
                           },1000);
            })(i);          
        }

Lasciatemi spiegare in modo semplice, quando una funzione ha creato non succede nulla finché non ha chiamato il ciclo for nel primo codice chiamato 5 volte ma non chiamato immediatamente quindi quando ha chiamato cioè dopo 1 secondo e anche questo è asincrono quindi prima che il ciclo for finisca e memorizzi il valore 5 in var i e infine eseguirlo setTimeout funzione cinque volte e stampa 5,5,5,5,5

Ecco come si risolve utilizzando IIFE, ovvero l'espressione della funzione di chiamata immediata

       (function(j){  //i is passed here           
            setTimeout(function(){
                           console.log(j);
                       },1000);
        })(i);  //look here it called immediate that is store i=0 for 1st loop, i=1 for 2nd loop, and so on and print 0,1,2,3,4

Per ulteriori informazioni, comprendere il contesto di esecuzione per comprendere la chiusura.

  • Esiste un'altra soluzione per risolvere questo problema utilizzando let (funzione ES6), ma dietro le quinte la funzione sopra funziona

     for(let i=0; i< 5; i++){           
         setTimeout(function(){
                        console.log(i);
                    },1000);                        
     }
    
    Output: 0,1,2,3,4
    

=> Ulteriori spiegazioni:

In memoria, quando esegui il ciclo for, fai come di seguito:

Ciclo 1)

     setTimeout(function(){
                    console.log(i);
                },1000);  

Ciclo 2)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Ciclo 3)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Ciclo 4)

     setTimeout(function(){
                    console.log(i);
                },1000); 

Ciclo 5)

     setTimeout(function(){
                    console.log(i);
                },1000);  

Qui non viene eseguito e quindi, dopo il ciclo completo, var ho memorizzato il valore 5 in memoria ma il suo ambito è sempre visibile nella sua funzione figlio, quindi quando la funzione viene eseguita all'interno setTimeout cinque volte che viene stampato 5,5,5,5,5

quindi per risolvere questo problema utilizzare IIFE come spiegato sopra.

Curry:Ti consente di valutare parzialmente una funzione passando solo un sottoinsieme dei suoi argomenti.Considera questo:

function multiply (x, y) {
  return x * y;
}

const double = multiply.bind(null, 2);

const eight = double(4);

eight == 8;

Chiusura:Una chiusura non è altro che l'accesso a una variabile al di fuori dell'ambito di una funzione.È importante ricordare che una funzione all'interno di una funzione o una funzione annidata non è una chiusura.Le chiusure vengono sempre utilizzate quando è necessario accedere alle variabili al di fuori dell'ambito della funzione.

function apple(x){
   function google(y,z) {
    console.log(x*y);
   }
   google(7,2);
}

apple(3);

// the answer here will be 21

La chiusura è molto semplice.Possiamo considerarlo così:Chiusura = funzione + il suo ambiente lessicale

Consideriamo la seguente funzione:

function init() {
    var name = “Mozilla”;
}

Quale sarà la chiusura nel caso di cui sopra?Funzione init() e variabili nel suo ambiente lessicale, ad esempio nome.Chiusura = init() + nome

Consideriamo un'altra funzione:

function init() {
    var name = “Mozilla”;
    function displayName(){
        alert(name);
}
displayName();
}

Quali saranno le chiusure qui?La funzione interna può accedere alle variabili della funzione esterna.displayName() può accedere al nome della variabile dichiarata nella funzione genitore, init().Tuttavia, se esistono, verranno utilizzate le stesse variabili locali in displayName().

Chiusura 1: funzione init + (nome variabile + funzione displayName()) --> ambito lessicale

Chiusura 2: funzione displayName + ( nome variabile ) --> ambito lessicale

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top