Can someone break down what's going on here clearly?
function timerCheck() {
for(var i=0; i<5; i++) {
setTimeout(function() {
console.log("Hello" + i);
}, 3000);
}
}
So as some of you may know, calling this function will not work as expected. What will end up happening is that this function will get called 5 times all at once with i set to 5 each time. This will be the output after 3 seconds:
Hello5
Hello5
Hello5
Hello5
Hello5
I also understand that using the setInterval method is the right way to approach this kind of problem, but I am curious what's going on under the hood here. I really want to understand how Javascript works. Please note that I do not have a computer science background, just a self-taught coder.
Variable scope in JavaScript is limited to functions.
In your example, the variable
i
is declared inside oftimerCheck
. This means that at the end of the loop,i
will be equal to5
.Now, adding in the call to
setTimeout
doesn't change the fact thati
is scoped totimerCheck
and thati
has been modified to equal5
by the time the code inside eachsetTimeout
call has run.You can create a function that "captures" the value of
i
so that when you call it from inside your loop you get new variable scope for thesetTimeout
call:Since
createTimer
takes a parameterj
, when you passi
from inside the for loop intimerCheck
tocreateTimer
,j
is now scoped tocreateTimer
so that eachsetTimeout
call has its ownj
.This might help you understand what's going on better:
You'll see
Immediately printed to the console, because all five iterations of the loop finish very quickly, and then after five seconds you'll see:
because the timeouts (which were all set at approximately the same time) all occur at once, and since the loop already finished:
i == 5
.This is caused by the scope of
i
. The variablei
has a scope of everywhere after it is declared intimerCheck();
There is no local i inside your anonymous function in setTimeout set there is novar i
, andi
isn't given as an argument to the function.You can fix this easily with a closure, which will return a function that has a local copy of i:
Which will output:
To understand this:
You have to know that a function can be executed immediately in Javascript. IE.
(function(x){ console.log(x); })('Hi');
printsHi
to the console. So the outer function above just takes in an argument (the current value ofi
) and stores it into a local variable to that function calledloc_i
. That function immediately returns a new function that prints"Hello" + loc_i
to the console. That is the function that is passed into the timeout.I hope that all made sense, let me know if you're still unclear on something.
This is actually an add-on to Andrews answer
If you try to set a variable that sets the output it explains the scope also.
as you can see the writes will be as expected but at the time the setTimeout fires the t variable will be the last set. Which will be Hello 4.
so the output will be
from the loop and
from the setTimeout