the scoping effect of the initialization block can be understood as if the declaration happens within the loop body, but just happens to be accessible within the condition and update parts.
๐
replit๏ผ
const { log } = console;
// โญโโ i โโโฎ <--- โญ `i` is "block-scoped"
for (let i = 0; i < 3; i++) {
// โญ every time "block scope" is entered,
// a new/different `i` is captured by closure.
//
// โญโ closure โโโฎ
setTimeout( () => log(i) , 1000); // 0, 1, 2 โญ
}
let j = 0; // โ `j` is in "outer scope"
for ( ; j < 3; j++) {
// โ every closure is capturing the same `j` variable
//
// โญโ closure โโโฎ
setTimeout( () => log(j) , 2000); // 3, 3, 3 โ (j = 3 after for-loop)
}
var keep1 = [];
// โญโโ i โโโฎ <--- โ "var" has no block scope
for (var i = 0; i < 3; i++) {
// โ every closure is keeping the "same" `i`.
keep1[i] = function keepI(){
return i;
};
}
var keep2 = [];
// โญโโ i โโโฎ <--- โญ "let" is block-scoped
for (let i = 0; i < 3; i++) {
// โญ `i` is block-scoped, every time block scope is entered,
// a new/different `i` is created & kept by closure.
keep2[i] = function keepI(){
return i;
};
}
[
keep1.map(f => f()), // โ [ 3, 3, 3 ]
keep2.map(f => f()), // โญ [ 0, 1, 2 ]
].forEach(x => log(x));