9

I know the difference between let and var. let is block scope and var is functional scope.

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

output : 3
         3
         3

I know how above code snippet is working(console.log(i) is executing at that time when value of i is 3, because scope of i is global).

But

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

output : 1
         2
         3

the above code snippet confusing me. according to me it should throw Reference Error(because the time when console.log(i) execute, will look the value of i in global scope not in local scope, and i is not declare/defined in global. so it should give reference error.)

Anyone who can explain how 2nd for loop working on Runtime ?

Mukund Kumar
  • 21,413
  • 18
  • 59
  • 79
  • 2
    Closure closes over the new instance of i for each iteration when using let. – Blindman67 Jun 17 '17 at 16:32
  • If a `Reference Error` would be thrown, then no kind of closure would work. Neither the one for the function scope `var`, nor the one for the `let`. – t.niese Jun 17 '17 at 16:33
  • Go and read this [article](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html) when you have time. It explains scoping, hoisting etc. really well. – Fahmi Jun 17 '17 at 16:44

3 Answers3

4

When you use let in this context, a new binding/scope is created at each iteration. If you want to achieve a similar behavior in ES5 with var, you have to use an IIFE:

for (var i = 0; i < 3; i++) {
  (function (i) {
    setTimeout(function () {
      console.log(i);
    }, 10);
  })(i);
}
Badacadabra
  • 8,043
  • 7
  • 28
  • 49
4

The second example (using let) works because a function will close over all variables that are in scope when it is declared. Each iteration of the for loop a new variable is being created with let, the function in the timeout closes over the variable and keeps a referance. When the function is dereferenced after the timeout, so are its closure variables.

See How do JavaScript closures work for more information on function closure.

Blindman67
  • 51,134
  • 11
  • 73
  • 136
4

This is the magic of closure. In side your loop

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

you are declaring a function

function(){
  console.log(i);
}

Additionally, the loop itself declares a block

for(let i=0; i< 3; i++){
  // this is a block scope because it is contained in 
  // braces
}

Variables defined with let are block scoped.

Because of closure, the function you declare inside the loop has access to all the variables declared in its scope and its parents scopes until it is garbage collected.

A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time that the closure was created.

The variable i is in-scope when the functions used by setTimeout are created. The i referred to is a different instance of i for each iteration of the loop.

The function exists until the interval you declared passes. That is why each of the 3 functions declared in your loop print the value of i; it was declared in the containing scope and remains available to the function.

Bert
  • 80,741
  • 17
  • 199
  • 164