JavaScript Variable Scope

Sto avendo un problema con qualche codice JavaScript.

copione

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

Uscite

5, 5, 5, 5, 5 invece di 1, 2, 3, 4, 5

Riesco a capire perché non funziona, ma mi chiedevo se qualcuno potesse spiegarmi cosa sta succedendo e perché non funziona!

Inoltre, come si può superare questo problema di ambito?

Le setTimeout callback setTimeout vengono eseguite in modo asincrono, tutte le chiamate console.log effettuate fanno riferimento alla stessa variabile i , e al momento in cui vengono eseguite, il ciclo for è terminato e i contiene 4.

Puoi racchiudere la tua chiamata setTimeout interna all’interno di una funzione accettando un parametro per memorizzare un riferimento a tutti i valori i che vengono iterati, qualcosa del genere:

 setTimeout(function() { for (var i = 0; i < 5; i++) { (function (j) { // added a closure to store a reference to 'i' values setTimeout(function() { console.log(j); }, j * 200); })(i); // automatically call the function and pass the value } }, 200); 

Controlla la mia risposta alla seguente domanda per maggiori dettagli:

  • Variabili nelle funzioni anonime - Qualcuno può spiegare quanto segue?

Dai un’occhiata a questa domanda . Potrebbe aiutarti a capire meglio la portata e le chiusure, molto simile alla tua domanda.

Stai cercando di creare una chiusura contenente la variabile “i”. Ma le chiusure vengono create solo alla fine di una funzione. Quindi se le tue funzioni sono create in un ciclo for , avranno tutti i valori dell’ultima iterazione.

Puoi sistemarlo con qualcosa del genere:

 var createFunction = function(index) { return function() { console.log(index); } }; for (var i = 0; i < 5; i++) { setTimeout(createFunction(i), i * 200); } 

dove si restituisce la funzione da un'altra funzione.

La variabile i esiste nell’ambito della funzione esterna.

Cambia durante il ciclo.

La funzione interna lo fa riferimento.

Prova qualcosa del genere:

 var i_print_factory = function (value) { return function () { console.log(value); }; }; var init_timers = function () { for (var i = 0; i < 5; i++) { setTimeout(i_print_factory(i), i * 200); } }; setTimeout(init_timers, 200); 

Perché stai accedendo alla stessa variabile i in tutte le funzioni utilizzate nel timeout impostato. La funzione setTimeout imposta la funzione per triggersre il numero di millisecondi in futuro sullo stesso thread della variabile i. Il valore i non viene copiato nella funzione, la funzione fa riferimento alla variabile effettiva i quando viene triggersta. Poiché hai eseguito il looping della funzione genitore fino a i = 5 e questo viene fatto prima che qualcos’altro abbia la possibilità di sparare, vengono visualizzati tutti come 5.