set_Timeout() Problem

What will the following program output?

To know the reason behind this behaviour, you need to have a little knowledge about the JavaScript Execution Model (Event Loop).

Code

function guessOutput() {
    // declaration using `var`
    for (var i = 0; i < 10; i++) {
        // Web API
        setTimeout(() => {
            console.log(i);
        });
    }
}
guessOutput();

Output

10
10
10
10
10
10
10
10
10
10

By asking this question, the interviewer basically wants to check your knowledge about variable declarations, scoping and intervals/timers in JavaScript.

You might have thought the result would be 0,1,2,...,9, but the actual output was much different. Why is this?

Upon examining the code snippet, we can make the following observations:

  • Variable i is declared using var (which has a function scope, rather than a block scope).
  • setTimeout() function is a part of Web APIs provided by web browsers (browser’s JS engine will take care of scheduling the execution of the specified callback function).
  • The delay parameter is not specified in the setTimeout() function (default argument is 0).

Because var has function scope, all the callbacks created by setTimeout() function will share the same variable i, which is incremented in the loop. When setTimeout() is called, the browser starts a timer and schedules the execution of the callback function after the specified delay (0 in this case). Once the delay has passed, and call stack is empty, the callback is placed in the callback queue. The event loop continuously checks the callback queue and moves the callback from the queue to the call stack for execution.

By the time the callback functions are executed, the loop would have been completed and the value of i would be 10. And since all the callbacks refer to the same i (with value 10), we get the output as mentioned above.

What if we want output as 0,1,2,...,9?

To achieve the above output, we can replace var with let. Using let will result in creation of block scope for each callback (with each iteration), and since each callback refers to its own private (and separate) variable i, the required output will be achieved.

What if we use const?

Using const will result in a TypeError. This is because const variables are read-only and cannot be incremented or modified after assignment.

The call stack will get empty when the function guessOutput() gets destroyed (completely finished executing). But if the function itself got destroyed, how will the setTimeout() function access the variable i?

Learn about closures here.