JavaScript for loop using setTimeout to pass argument

When using a for loop with setTimeout, you may encounter unexpected behavior.

Consider the following code. What do you expect the console to display?

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

You may have expected this:

var is now 0
var is now 1
var is now 2
var is now 3
var is now 4

The code actually results in:

var is now 5
var is now 5
var is now 5
var is now 5
var is now 5

The reason is that the code is evaluated at runtime. When the first setTimeout function fires, the referenced variable i is now set to 5; the same is true for the subsequent firings of setTimeout functions.

Option #1: Use JavaScript Closures

Use setTimeout with a JavaScript for loop:

var time = 0;
for (var i = 0; i < 5; i++) {
    time += 1000;
    setTimeout(function(j) {
        return function() {
            console.log("var is now", j);
        }
    }(i), time);
}

Option #2: Replace var with let

Replace var with let. Unlike the "var" keyword, which defines a variable globally, using "let" declares a block scope local variable. Each iteration causes a separate instance of the variable.

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

9 comments

  1. anonymous

    That saved me a few hairs! Nice one

  2. anonymous

    Thanks man, really helped me!

  3. anonymous

    Great!

  4. anonymous

    Thanks!!!

  5. anonymous

    Thanks !! helped a lot

  6. anonymous

    Nice!

  7. anonymous

    Thanks that was asome

  8. anonymous

    Thanks! This script helps me a lot, i really apreciate it.

  9. anonymous

    Thx!

    It helps!

Leave a Reply