我在使用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
}
答案 0 :(得分:2)
调用您的函数后,i
等于commands.length
而commands[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>