-1

I know let is scoped to the nearest enclosing block. but still dont understand why below given code is output so differently.

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

//0,1,2,3,4

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

//5,5,5,5,5

George
  • 6,630
  • 2
  • 29
  • 36
Jitender
  • 7,593
  • 30
  • 104
  • 210
  • 6
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let Read the description – epascarello Mar 20 '17 at 15:42
  • 1
    Upvoting. Even though this is a duplicate, and the OP should have searched a bit more, I find this question title, question body, and tymeJV's answer clearer for than in the dupe. – labyrinth Mar 29 '17 at 14:03

1 Answers1

5

The second outputs like so because the time your timeout actually runs, i is set to the last iteration. Why? Because if you use var in your for the variable is hoisted outside the loop scope, so it actually looks like:

var i = 0;
for (i=0;i<5;i++){
    //and when your timeout runs, i is 5
}
console.log(i); //5

And let doesn't hoist outside:

for (let i=0;i<5;i++){

}
console.log(i); //undefined, not hoisted
tymeJV
  • 103,943
  • 14
  • 161
  • 157
  • and let is the oposite. – Nelson Teixeira Mar 20 '17 at 15:43
  • Brilliant! So, while the timeout is still running the var `i` is incrementing its value, right? That same function without the timeout would result in the same output in both cases (with let & with var), right? – SrAxi Mar 20 '17 at 15:46
  • @SrAxi that's correct – George Mar 20 '17 at 15:46
  • 3
    The final value of `i` is 5, not 4. The final-expression (`i++`) is evaluated at the end of the loop iteration, before the next evaluation of the condition (`i<5`) . – Gerardo Furtado Mar 20 '17 at 15:48
  • @GerardoFurtado -- Woops, thanks for that, made the edit! (And I actually didnt realize that final expression was eval'd... learn something new all the time) – tymeJV Mar 20 '17 at 15:50