This is all related to the scope of the variable. Let's try to wrap both the pieces into functions, and observe the output:
function test() {
// `i` will be declared here, making it a non-for-loop scoped variable
const arr = [1, 2, 3, 4];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log(arr[i])
}, 1000);
} // Prints undefined 5 times
}
test();
So in the first case, i
will be hoisted, and because of the asynchronous nature of setTimeout
, i
will immediately become 4 as the loop ends without waiting. This will make arr[i]
to point to an undefined
element in the array.
In the second case, i
is not hoisted, and has scoped access to each iteration of the loop, making i
accurately available to console.log
statement. Thus the results are as per the expectations:
function test() {
const arr = [1, 2, 3, 4];
for (let i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log(arr[i])
}, 1000);
} // Prints all the values correctly
}
test();