Petr Hofman Petr Hofman - 6 days ago 6
Javascript Question

Variable is lost when passed as a parameter in setTimeout()

I have a problem with calling a function with a parameter inside a setTimeout function. Basically I'm trying to make a small online game, where I create a queue of commands and then execute them one at a time (each takes some time to show a visualization).

Unfortunately it seems that I cannot pass any variable as a parameter inside the setTimeout(). Although the variable does exist when I call the function it does not exist later when it is executed. The function doesn't keep track of the passed value.

Is there any solution to this? Thanks a lot for any help. Here is a code I use:

function executeCommands() {
var commands = document.getElementsByClassName("cmdplace");
var timeout = 0;
for (i = 0; i < commands.length; i++) {
console.log(commands[i].childNodes[0]); //variable exists
setTimeout(function() {go(commands[i].childNodes[0]);}, timeout+=400); //Uncaught TypeError: Cannot read property 'childNodes' of undefined
console.log(commands[i].childNodes[0]); //variable still exists
}
}

function go(command) {
//do somethig based on the passed command
}

Answer

When your functions are invoked, i is equal to commands.length and commands[i] is undefined.
They are capturing the variable i, not its value.
When they execute, they get out of i the actual value, but so far it has reached commands.length (that is the condition used to break your loop).

You can do something like this to work around it:

setTimeout(function(j) {
    go(commands[j].childNodes[0]);
}.bind(null, i), timeout+=400);

Or this:

setTimeout((function(j) {
    return function() {
        go(commands[j].childNodes[0]);
    };
})(i), timeout+=400);

Note also that, as you defined it, i is a global variable.

Comments