This question already has an answer here:
I'm having a problem with some JavaScript code.
Script
setTimeout(function() {
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, i * 200);
}
}, 200);
Outputs
5, 5, 5, 5, 5 instead of 1, 2, 3, 4, 5
I can kind of understand why this doesn't work, but I was wondering if someone could explain to me what's happening and why it's not working!
Also, how can this scope problem be overcome?
Because you are accessing the same variable i in all the functions used in set timeout. The setTimeout function sets the function to fire the number of milliseconds in the future on the same thread as the i variable. The i value isn't copied in the function, the function is referencing the actual variable i when it is fired. Because you have looped through parent function until the i = 5 and this is done before anything else has a chance to fire, they all show up as 5.
The variable
i
exists in the scope of the outer function.It changes as the loop runs.
The inner function references it.
Try something like this:
The
setTimeout
callback functions are executed asynchronously, all theconsole.log
calls you make refer to the samei
variable, and at the time they are executed, the for loop has ended andi
contains 4.You could wrap your inner
setTimeout
call inside a function accepting a parameter in order to store a reference to all thei
values that are being iterated, something like this:Check my answer to the following question for more details:
You're trying to create a closure containing the variable "i". But closures are only created at the end of a function. So if your functions are created in a for loop, they will all have the values from the last iteration.
You can fix it with something like this:
where you return the function from another function.
Take a look at this question. It might help you understand the scope and closures better, very similar to your question.