Âmbito da variável JavaScript

Estou tendo um problema com algum código JavaScript.

Roteiro

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

Saídas

5, 5, 5, 5, 5 em vez de 1, 2, 3, 4, 5

Eu meio que entendo porque isso não funciona, mas eu queria saber se alguém poderia me explicar o que está acontecendo e porque não está funcionando!

Além disso, como esse problema de escopo pode ser superado?

As funções de retorno de chamada setTimeout são executadas de forma assíncrona, todas as chamadas console.log feitas referem-se à mesma variável i e, no momento em que são executadas, o loop for terminou e i contém 4.

Você poderia envolver sua chamada setTimeout interna dentro de uma function aceitando um parâmetro para armazenar uma referência a todos os valores i que estão sendo iterados, algo assim:

 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); 

Confira minha resposta para a seguinte pergunta para mais detalhes:

  • Variáveis ​​em Funções Anônimas - Alguém pode explicar o seguinte?

Dê uma olhada nesta questão . Isso pode ajudá-lo a entender melhor o escopo e os fechamentos, muito semelhantes à sua pergunta.

Você está tentando criar um fechamento contendo a variável “i”. Mas os fechamentos são criados apenas no final de uma function. Portanto, se suas funções forem criadas em um loop for , todas elas terão os valores da última iteração.

Você pode consertar isso com algo parecido com isto:

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

onde você retorna a function de outra function.

A variável i existe no escopo da function externa.

Ele muda conforme o loop é executado.

A function interna faz referência a ele.

Tente algo assim:

 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); 

Porque você está acessando a mesma variável i em todas as funções usadas no tempo limite definido. A function setTimeout define a function para triggersr o número de milissegundos no futuro no mesmo segmento da variável i. O valor i não é copiado na function, a function está referenciando a variável real i quando é triggersda. Como você passou pela function-mãe até o i = 5 e isso é feito antes que qualquer outra coisa tenha a chance de triggersr, todos eles aparecem como 5.