From You Don't Know JS:
for (var i=1; i<=5; i++) {
setTimeout( function timer(){
console.log( i );
}, i*1000 );
}
gives
6
6
6
6
6
but using an IIFE like so
for (var i=1; i<=5; i++) {
(function(){
var j = i;
setTimeout( function timer(){
console.log( j );
}, j*1000 );
})();
}
gives
1
2
3
4
5
My question: why doesn't
for (var i=1; i<=5; i++) {
setTimeout( function timer(){
var j = i;
console.log( j );
}, i*1000 );
}
or
for (var i=1; i<=5; i++) {
function timer() {
var j = i;
console.log(j);
}
setTimeout(timer, i*1000 );
}
work like the IIFE example? It seems to me they both have a function
declaration with a new variable j
, wouldn't that create a new lexical scope with a specific setting for i
?
The important part of the IIFE is that it runs right away; before i
changes, it reads its value and puts it in a new variable. The function reading i
in your other examples – function timer()
– does not run right away, and the value it puts in its new variable is the value of i
after it’s already changed.
Also, in ES6, you can just let i = …
instead of var i = …
and it’ll work fine without the IIFE or j
:
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i);
}, i * 1000);
}
because let
has block scope instead of function scope and variables declared in the initialization part of for
loops count as being half-inside the for
’s block.