在setTimeout()

时间:2016-11-25 23:00:07

标签: javascript settimeout

我在使用setTimeout函数内的参数调用函数时遇到问题。基本上我正在尝试制作一个小型在线游戏,我在其中创建一个命令队列,然后一次执行一个(每个都需要一些时间来显示可视化)。

不幸的是,我似乎无法将任何变量作为setTimeout()内的参数传递。虽然变量在我调用函数时确实存在,但是在执行它时它不存在。该函数不跟踪传递的值。

这有什么解决方案吗?非常感谢您的帮助。这是我使用的代码:

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
}

2 个答案:

答案 0 :(得分:2)

调用您的函数后,i等于commands.lengthcommands[i]等于undefined
他们正在捕捉变量i,而不是它的价值 当它们执行时,它们会超出i的实际值,但到目前为止它已达到commands.length(这是用于打破循环的条件)。

你可以做这样的事情来解决它:

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

或者这个:

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

另请注意,正如您所定义的那样,i是一个全局变量。

正如@PMV的评论中提到的,在现代JavaScript中有一种更简单的方法(如果这是你的选择)。
只需使用let语句,如下所示:

for (let i = 0; i < commands.length; i++) {
    // do whatever you want here with i
}

这将确保每次迭代都获得一个名为i的新变量,您可以像在原始代码中一样捕获它。

答案 1 :(得分:0)

您需要为每个项目制作一份明确的副本。到setTimeout运行时,循环已经完成。

var timeout = 0;

function executeCommands() {
    var commands = document.getElementsByClassName("cmdplace");
    
    for (i = 0; i < commands.length; i++) {
          go(commands[i]);
    }
}

function go(command) {
  setTimeout(function() {
     console.log(command);
  }, timeout += 400);  
}

executeCommands();
<ul>
  <li class="cmdplace">A</li>
  <li class="cmdplace">B</li>
  <li class="cmdplace">C</li>
  <li class="cmdplace">D</li>
</ul>