Many mistakes in section 2. The author seems to fundamentally misunderstand block scoping vs lexical scoping, and interactions when deferring execution to the next run of the event loop.
In the first example:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i));
}
// prints "0 1 2" — as expected
let i = 0;
for (i = 0; i < 3; i++) {
setTimeout(() => console.log(i));
}
// prints "3 3 3" — what?
i's scope is
outside the for loop in the second example,
and the setTimeouts execute in the call stack (e.g. the next run of the event loop), after i has finished incrementing in the first event loop iteration
Consider that you'd have the same issue with the older `var` keyword which is lexically scoped
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i));
}
// prints "3 3 3" because i is not block-scoped
If for some reason you really need some work run in the next call stack,
and you need to use the value of a variable which is scoped outside the loop and modified inside the loop, you can also define a function (or use an iife) to pass the value of i in the current iteration into (rather than getting the reference of i in the event loop's
next call stack)
let i = 0;
for (i = 0; i < 3; i++) {
(
(x)=>setTimeout(()=>console.log(x))
)(i)
}
// prints 1 2 3
In the first example:
i's scope is outside the for loop in the second example, and the setTimeouts execute in the call stack (e.g. the next run of the event loop), after i has finished incrementing in the first event loop iterationConsider that you'd have the same issue with the older `var` keyword which is lexically scoped
If for some reason you really need some work run in the next call stack, and you need to use the value of a variable which is scoped outside the loop and modified inside the loop, you can also define a function (or use an iife) to pass the value of i in the current iteration into (rather than getting the reference of i in the event loop's next call stack)