Interview Round

Screening/Early rounds.

You can expect this Javascript interview question sometime in your screening or early rounds. No surprises if you see problems based on this concept during later stages of your interview as well.

Concepts Used

Scopes and Closures. Async JS.

You need a good level of understanding on scopes and how closures work in Javascript to answer this. There can be different variations of this problem.

Have a look at the code snippet below. What should be the expected output?

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

Is this your answer?

0
1
2

If yes, take my advice, cancel all your planned Javascript/Front-end interviews right now. You are not prepared for the interview yet. Yes, Seriously!

That's a common mistake candidates make. But trust me, this mistake is enough to raise a red flag.

Correct Answer

3
3
3

We have a closure here. The inner anonymous function passed to setTimeout has access to its outer scope variable i. If you know how timers work, the function supplied to setTimeout won't execute right away. It would be added to the event loop when the 200ms timer expires.

Due to presence of a closure, the anonymous function will still have access to the variable i, even when the for loop has finished execution. That means by the time the any of the three anonymous function executes, the value of i would be 3 (end of loop).

All three anonymous functions will have access to the same i. Please note - Separate copies of i are not passed to each of the anonymous functions.

So each of them will print the latest value of i.

Follow Up Question

What if we change the timer from 200ms to 0?

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

Ah! that's an easy one. Now it should be:

0
1
2

Not really, that's a wrong answer.

Another common wrong answer I've heard is that it could be anything between 0 - 3, because we don't know when the timeout will execute.

Timers don't work that way. Even if you set the timeout to 0, the anonymous function won't execute right away. It would be added to the event queue. So, the for loop would have definitely finished executing before any one of these anonymous function does. Correct answer stays the same.

3
3
3

Closures within loops - How to fix it?

To fix closures within loop, you need to somehow create a copy of i and pass that copy to your inner function. Here's how you do that:

Solution #1

Use IIFE (Immediately Invoked Function Expression)

An IIFE gets executed as soon as it is defined. Value of i during that particular iteration is copied and a new lexical scope is generated for each of these functions.

So, the anonymous functions passed to setTimeout will now refer to different copies of j. And you'll get the expected result.

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

Using the same approach, you can just pass i  down as a function parameter.

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

Solution #2 (Recommended)

Replace var with  let to create the iteration variable. let is block scoped. So unlike a var, a the same lexical scope is not shared between different iterations of the for loop. A new lexical scope is created for each iteration. Each anonymous function passed to setTimeout will now have access to a different value of i.

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

This particular code example of closures within loops in Javascript is pretty common. You'll generally see variations of it being asked in interviews. You should just try to look for the pattern discussed below.

Pattern for Closures within loop problems

  • A for loop with an iteration variable declared with a var
  • An inner function that uses the iteration variable
  • The inner function does not get invoked immediately (Tip: Look for async operations here)

Other common examples of inner functions can be event handlers or callback functions that don't get executed immediately.

That's all folks. I hope you have a better idea of the concept of closure within loops in Javascript now. All the best for your Javascript interview!