This might help you understand what's going on better:
function timerCheck() {
for(var i=0; i<5; i++) {
console.log("Hi" + i);
setTimeout(function() {
console.log("Hello" + i);
}, 3000);
console.log("Bye" + i);
}
}
You'll see
Hi0
Bye0
Hi1
Bye1
Hi2
Bye2
Hi3
Bye3
Hi4
Bye4
Immediately printed to the console, because all five iterations of the loop finish very quickly, and then after five seconds you'll see:
Hello5
Hello5
Hello5
Hello5
Hello5
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 variable i
has a scope of everywhere after it is declared in timerCheck();
There is no local i inside your anonymous function in setTimeout set there is no var i
, and i
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:
function timerCheck() {
for(var i=0; i<5; i++) {
setTimeout((function(loc_i) {
return function() {
console.log("Hello" + loc_i);
};
})(i), 3000);
}
}
Which will output:
Hello0
Hello1
Hello2
Hello3
Hello4
To understand this:
(function(loc_i) {
return function() {
console.log("Hello" + loc_i);
};
})(i)
You have to know that a function can be executed immediately in Javascript. IE. (function(x){ console.log(x); })('Hi');
prints Hi
to the console. So the outer function above just takes in an argument (the current value of i
) and stores it into a local variable to that function called loc_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.