DEV Community

Cover image for JavaScript Closure Simply Explained

JavaScript Closure Simply Explained

Phillip Shim on July 26, 2019

  A closure is a stateful function that is returned by another function. It acts as a container to remember variables and parameters from its pare...
Collapse
 
jmergenthal profile image
Jurian Mergenthal • Edited

Just a small addition:
instead of

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

you can also just use let, instead of var here:

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

since let variables are bound to the block scope :)

Collapse
 
yamalight profile image
Tim Ermilov • Edited

The code in the final example is actually wrong:

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

If you write like this, you might as well remove setTimeout completely as it's not doing anything here (try setting timeout to 10s and see if it prints out the result after 10s).
What you are doing is this:

function printIndex(index) {
  console.log(index)
}

for(var i=0; i<5; i++) {
  setTimeout(printIndex(i), 1000)
}

This will just print out all index immediately and setTimeout will have no effect.
To fix this - you either need to return a function, or using bind when setting a timeout, e.g.:

function printIndex(index) {
  return () => console.log(index)
}

for(var i=0; i<5; i++) {
  setTimeout(printIndex(i), 1000)
}
Collapse
 
shimphillip profile image
Phillip Shim • Edited

Oops. you are totally correct, forgot to return a function!. I appreciate you pointing this out. Will fix the code example!

Collapse
 
bigschatz profile image
bigschatz

Hi Phillip,

Thank you for writing this great article on closures. The practical examples are easy to understand.

I wonder how, in the last example of the for loop, could you refactor the example so that each index prints out after the setTimeout value has elapsed

Like this:
0 (...1000ms have passed)
1 (...1000ms have passed)
2 (...1000ms have passed)
3 (...1000ms have passed)
4 (...1000ms have passed)
5 (loop exits)

Collapse
 
shimphillip profile image
Phillip Shim

Sure just made an edit!

Collapse
 
bigschatz profile image
bigschatz

I see that you made the edit!

But that is not actually what happens when you run the code.

The code you wrote prints 0-4 (all indexes) after 2000ms all at once.

I was curious how to make a loop that prints out each index, one at a time, according to the setTimeout value.

Maybe this isn't possible using a for loop.

I hope that makes sense!!

Thread Thread
 
jaydeepkarena profile image
Jaydeep Karena

They print all at once because all setTimeout starts at same time and for all setTimeout 1 second passes at same time. What you want can be achieved by passing timeout values to 1000, 2000, 3000....

Following code will give you that output:

for(var i=0; i<5; i++) {
  setTimeout((function(index) {
    return function() {
      console.log(index);
    }
  }(i)), 1000 * i)
}
Collapse
 
rctryoka profile image
Robert Carlo Tubig • Edited

in the interview question about closure
why does it shows a different result when you use let in the for loops ?

Collapse
 
salyadav profile image
Saloni Yadav

let is a block scope. so the value of i gets captured. in case of var its a global scope/scope of where the function is called. so when the function actually executes, the var i value is the last standing value, which is not the case with let.