loading...

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... [Read Full]
markdown guide
 

Just a small addition:
instead of

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

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

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

since let variables are bound to the block scope :)

 

Thanks Jurian! I debated if I should include this solution in my article because I just wanted to focus on closure but I am glad you brought it up :)

 

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)
}
 

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

 

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)

 
 

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!!

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)
}
 

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

code of conduct - report abuse