Tricky Questions 1

Intro

We often have to mentally run through a piece of code and play “be the compiler” to either answer an interview question, or more importantly, debug a piece of code that is not behaving as we want or expect.

What follows is a bunch of somewhat, subjectively tricky pieces of code with explanation on how they work in terms of scope, runtime, event loop and whatnot.

Loop and Timeouts

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

What does the code above output?

  1. undefined

  2. Numbers 1, 2 and 3 logged.

  3. Number 3 alerted three times.

  4. Number 0 logged three times.

Show me!

Letter “d” is correct. The number 3 is logged three times.

The loop has to run immediately without pause. But setTimeout will cause the callback function to be enqueued into the event loop.

The callback inside the timeout is logging the i variable from the outer scope. By the time the timeout runs out, the value if i has already been set to 3 due to the increment in the loop (++i).

We can even replace 500 with 0 as the second parameter for the timeout. The callback will still be enqueued to be run only after the loop is finished, which will still cause 3 to be logged three times.

Loops and Timeouts again

Expanding from the example above, still using a for loop, still using var, how to somehow capture each value of i so it logs 0, 1 and 2?

Show me!

An IIFE function with a param to capture each value of i does the trick:

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

Note the IIFE (immediately invoked function expression) that captures the value of i on each loop, which is then available in the setTimeout closure through n.

Because of the IIFE being passed i on each loop, it captures the value of i at that “moment”, so to speak. Then when log(n) happens, it references each value captured by the closure correctly and the output is 0, 1 and 2 respectively.