Loop with var and setTimeout
Because of two things at once:
varhas function scope. In the loopfor (var i = 0; i < 3; i++) { ... }, only oneivariable is created for the whole function, not a new one per iteration. EverysetTimeoutcallback closes over the same value ofi.setTimeoutruns later. Callbacks land in the macrotask queue and run after the current JS stack empties out. By the time the first timer fires, the loop has already finished, andiholds its final value (for example, 3).
The symptom
javascript
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0);
}
// 3
// 3
// 3How to fix it
Option 1 - let (block scope):
javascript
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 0); // 0, 1, 2
}Option 2 - an IIFE/closure that passes the current i:
javascript
for (var i = 0; i < 3; i++) {
(function (j) {
setTimeout(() => console.log(j), 0); // 0, 1, 2
})(i);
}Option 3 - pass it as an argument to setTimeout:
javascript
for (var i = 0; i < 3; i++) {
setTimeout(j => console.log(j), 0, i); // 0, 1, 2
}Option 4 - bind:
javascript
for (var i = 0; i < 3; i++) {
setTimeout(console.log.bind(null, i), 0); // 0, 1, 2
}In short:
vargives you one "shared" variable for the whole loop, andsetTimeoutruns after the loop has already finished. Uselet, or isolate the value through a closure or an argument.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.