Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between let and var inside setTimeout? [duplicate]

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 ?

like image 627
Mukund Kumar Avatar asked Jun 17 '17 16:06

Mukund Kumar


People also ask

What is the difference between LET and VAR?

let is block-scoped. var is function scoped. let does not allow to redeclare variables. var allows to redeclare variables.

Which is faster VAR or let?

In terms of performance comparison, var is faster and let is slower inside the loops while running or executing the code. Re-declaring var declared a variable in the same function or scope gives rise to Syntax Error whereas let declared variable cannot be redeclared.

Why is var better than let?

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.

Should I use VAR or let?

Use let when you know that the value of a variable will change. Use const for every other variable. Do not use var.


3 Answers

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.

like image 59
Blindman67 Avatar answered Oct 23 '22 17:10

Blindman67


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.

like image 21
Bert Avatar answered Oct 23 '22 18:10

Bert


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);
}
like image 25
Badacadabra Avatar answered Oct 23 '22 17:10

Badacadabra