Here is an example of what is the underlying problem. It is a problem of "closures". It is a complicated topic that a lot of JS developers don't understand.
function withLet() {
for (let i = 0; i < 3; i++) {
const expectedI = i;
setTimeout(() => {
console.log('withLet', { expectedI, actualI: i });
});
}
}
function withVar() {
for (var i = 0; i < 3; i++) {
const expectedI = i;
setTimeout(() => {
console.log('withVar', { expectedI, actualI: i });
});
}
}
withLet();
withVar();
About why...
The var
keywork creates the variable in the scope of the function withVar
. If any function inside of the withVar
function needs to access the i
variable it will get the reference shared between all of the iterations of the loop.
All functions, be it event handlers or simple setTimeout
will thus get the reference of the variable after all synchronous code has run.
The let
keyword created a new closure, one closure per loop iteration, thus if any function inside the for loop needs to access i
, it will get the reference of its own and only i
.
for (let i = 0; i < 3; i++) {
const expectedI = i;
setTimeout(() => {
console.log('withLet', { expectedI, actualI: i });
});
}
console.log(i); // Error! Variable "i" is not defined!