1. let i in the scope of the loop
At first glance, i in for(let i = 0;...) seems to be in an outer scope, not in the scope of the loop, but it's actually in the scope of the loop, it make sense to think about how for work like this:
for(let i = 0;i<3;i++){ // let i=0,it's actually in the scope of the loop
setTimeout(()==>console.log(i));
}
//just like below
{ // a fictional variable for illustration
let $$i = 0; for (; /* nothing */ $$i < 3; $$i++) { // here's our actual loop `i`!
let i = $$i;
setTimeout(() => console.log(i));
}
// 0
// 1
// 2
}
for(let i=0;i<3;i++){
setTimeout(()=>console.log(i),0)
}
//The explanation is that a `for` loop has an own scope for every iteration. We can see that well by looking at the code that is generated if we transpile the `for` loop (using `let`) from above down to ES5 using Babel:
var _loop = function _loop(i) {
setTimeout(function () {
return console.log(i);
}, 0);
};
for (var i = 0; i < 3; i++) {
_loop(i);
}
2. i gets a new binding for every iteration of the loop.
var-declaring a variable in the head of a for loop creates a single binding (storage space) for that variable:
const arr = [];
for (var i=0; i < 3; i++) {
arr.push(() => i);
}
arr.map(x => x()); // [3,3,3]
Every i in the bodies of the three arrow functions refers to the same binding, which is why they all return the same value.
If you let-declare a variable, a new binding is created for each loop iteration:
const arr = [];
for (let i=0; i < 3; i++) {
arr.push(() => i);
}
arr.map(x => x()); // [0,1,2]
This time, each i refers to the binding of one specific iteration and preserves the value that was current at that time. Therefore, each arrow function returns a different value.