I was going through closures in javascript, found something interesting.

for(var i = 0; i < 3; ++i) {
    console.log(setTimeout(() => {
	console.log(i);
    }
    ), 1000);
};

/*
output
3
3
3
*/

This is pretty much what we expect, after 1 second value of i will be 3, then setTimout call the callback fn, when callback try to reference i, it’s value will be 3 in that environment. Ok, let’s move to next example.

let i;
for(i = 0; i < 3; ++i) {
    console.log(setTimeout(() => {
	console.log(i);
    }), 1000)
}

/*
output:
3
3
3
*/

that’s also like previous example, let’s try another one. let’s declare i inside for

for(let i = 0; i < 3; ++i) {
    console.log(setTimeout(() => {
	console.log(i);
    }), 1000)
}

/*
output:
0
1
2
*/

Well 😱, what just happened?

If there is let declaration in the head of for, the variable will be declared for each iteration. for more info checkout this stack overflow answer

before this, I was having this mental model of for loop

{
 let i = 0;
 if(i < 3){
  setTimeout(...)
  i += 1;
  }
 if(i < 3){
  setTimeout(...)
  i += 1;
  }
 if(i < 3){
  setTimeout(...)
  i += 1;
 }
}

Now if we use let in for loop header

{
    let i = 0;
    {
	let i = prev_i;
	if (i < 3){
	    setTimeout(...)
	    i++;
	}
    }
    {
	let i = prev_i;
	if (i < 3){
	    setTimeout(...)
	    i++;
	    }
    }
    {
	let i = prev_i;
	if (i < 3){
	    setTimeout(...)
	    i++;
	}
    }
}

so now each callback fn in setTimeout can correctly access the i in those iteration.