2013-10-30 25 views
33

→ jsFiddleUn JavaScript chiusura confusione

function f1(){ 
    var n=999; 

    nAdd=function(){n+=1;}; 

    function f2(){ 
     alert(n); 
    } 
    return f2; 
} 

var result = f1(); 
var result2 = f1(); 

result(); // 999 
nAdd(); 
result2(); // 1000 
result2(); // 1000 
result(); // 999 

Sto cercando di imparare JavaScript chiusure, ma il codice di cui sopra appena mi ha fatto confuso. Quando la prima volta si chiama result(), è 999. Va bene per me.

Dopo nAdd() si chiama, result2() spettacoli 1000. E credo che questo sia dovuto a funzionare result2() e la funzione result() sono uguali per funzionare f1().

Ma perché l'ultimo result() mostra 999 anziché 1000?

risposta

36

Ogni volta viene chiamato f1() che crea una nuova chiusura con la propria variabile locale n.

Tuttavia, la variabile nAdd è globale, e così viene sovrascritto ogni volta f1() si chiama - il che significa chiamare nAdd() sarà sempre e solo aggiungere alla variabile n nell'ultimo chiusura .

UPDATE: Se si vuole essere in grado di incrementare i valori di n in ogni chiusura in modo indipendente si potrebbe fare qualcosa di simile:

function f1(){ 
    var n=999; 
    return { 
     incrementN : function(){n+=1;}, 
     getN : function f2(){console.log(n);} 
    } 
}  
var result = f1(); 
var result2 = f1(); 
result.getN(); // 999 
result.incrementN(); 
result2.getN();//999 
result2.incrementN(); 
result2.getN();//1000 
result.getN();//1000 

Cioè, hanno f1() restituire un oggetto che contiene due metodi che non sono dichiarati come globali e che entrambi funzionano sulla variabile locale n dalla chiusura a cui appartengono.

4

result e result2 contengono il risultato di diverse chiamate di f1 e quindi contenere diverse istanze della variabile locale n. Ogni invocazione di una funzione può avere valori diversi per le variabili locali di quella funzione. Ciò vale anche quando non sono coinvolte chiusure.

+1

+1. Ogni volta che viene immesso un contesto di esecuzione, viene creato un nuovo set di variabili. – RobG

13

Ogni volta che si chiama f1() voi:

  • Creare una nuova variabile (locale) chiamato n con un valore di 999
  • Creare una nuova funzione senza nome assegnato al globalenAdd che modifica che n (e sovrascrive qualsiasi funzione precedente assegnata a nAdd)
  • Creare una nuova funzione restituita che avvisi il valore di tale n

Si chiama f1() due volte, quindi si fa tutto questo due volte. La seconda volta che lo chiamate, si sovrascrive lo nAdd con una nuova funzione che modifica lo secondon.

Questo vi lascia con:

  • result() che avvisa il priman
  • result2() che avvisa il secondon
  • nAdd() che incrementa la secondon

result() sull'ultima riga Allerte 999 perché avverte il valore del priman (che non è mai stato incrementato).

+2

La variabile * nAdd * viene creata una volta: la prima volta * f1 * viene chiamato nel punto in cui viene valutata l'istruzione di assegnazione. Dopodiché, è solo il valore che cambia ogni volta che viene chiamato * f1 *. Forse è solo un altro modo per dire quello che hai detto. : -/ – RobG

1

La riga nAdd=function(){n+=1;}; crea una funzione globale che è una chiusura all'interno di f1(). Una chiusura ha accesso anche a tutte le variabili dall'ambito della funzione che lo ha creato. Così ogni volta che si chiama f1() crea una nuova funzione nAdd() che ha n valore legato al valore della var n della chiamata di f1().

Nel codice;

var result = f1(); 
var result2 = f1(); 
result(); // 999 
nAdd();   // Created by "var result2 = f1();" and has the same 'n' value as function in result2 
result2();//1000 
result2();//1000 
result();//999 
0

il risultato e il risultato2 creano due chiusure diverse con diverso n. Se si crea una variabile globale na dichiarandola fuori dalla funzione f1(), si otterrà il risultato atteso poiché in tal caso si accederà sempre alla variabile globale n:

var n = 999; funzione f1() {
nAggiungi = function() {n + = 1;};
F2() {
console.log (n);
}
ritorno f2;
}
var result = f1();
var result2 = f1();
risultato(); // 999
nAdd();
result2(); // 1000
result2(); // 1000
risultato(); // 1000

27

Ci sono già buone risposte, ma credo che un quadro sarebbe utile capire.

enter image description here

+8

+1 Questo è un modo molto creativo! – ComFreek

+1

finalmente cliccato.grazie per aver visualizzato – Moak

+0

@Moak: prego. –

0

quel modo:

var nAdd; 
function f1(){ 
    var n=999; 

    nAdd=function(){n+=1;}; 

    function f2(){ 
     alert(n); 
    } 
    return f2; 
} 

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999 

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999 

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999 

nAdd(); 

result(); // 999 

result2(); // 999 

result3(); // 1000 

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999 

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999 

nAdd(); 

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999 


result(); // 999 

result2(); // 1000 

result3(); // 999 

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999 

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999 

nAdd(); 

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999 
nAdd(); 
nAdd(); 
nAdd(); 

result(); // 999 

result2(); // 1000 

result3(); // 1002 
+0

Ti piacerebbe aggiungere una spiegazione alla tua soluzione di codice? –

+0

Immagino che questo tizio mostri 3 frammenti, ognuno dei quali termina con il codice "result3();". Quindi può essere capito. – CoolGuy