当我在greasemonkey脚本中的for()循环中使用setTimeout()时,它似乎根本不起作用。但是,如果我在Firebug控制台中运行它,完全相同的代码工作正常。这是代码:
// ==UserScript==
// @name setTimeout test
// @include *
// @run-at document-end
// ==/UserScript=
function test(delaytime) {
alert("test called with "+delaytime);
}
function test2() {
for( var i = 0; i < 100; i+= 10 ) {
setTimeout('test('+i+');', i);
}
}
setTimeout(test2,10);
如果我用如下所示的显式调用替换for()循环,那么它可以正常工作。
setTimeout(function() { test( 0); }, 0);
setTimeout(function() { test(10); }, 10);
setTimeout(function() { test(20); }, 20);
setTimeout(function() { test(30); }, 30);
setTimeout(function() { test(40); }, 40);
setTimeout(function() { test(50); }, 50);
setTimeout(function() { test(60); }, 60);
setTimeout(function() { test(70); }, 70);
setTimeout(function() { test(80); }, 80);
setTimeout(function() { test(90); }, 90);
有什么区别?有什么方法可以让for循环生成的setTimeouts在greasemonkey中工作吗?
答案 0 :(得分:3)
因为当setTimeout为了执行函数而触发时,字符串被唤醒,循环运行它的过程并且i
位于循环的最后一个值。
要为每次调用setTimeout冻结i
的值,您需要在函数闭包中捕获它,如下所示:
function test2() {
for( var i = 0; i < 100; i+= 10 ) {
setTimeout(function(val) {
return(function() {test(val);});
} (i), i);
}
}
这样做的好处是可以去除setTimeout参数中的eval。
答案 1 :(得分:1)
您必须将i
的值复制到本地范围的变量中:
function test2() {
for( var i = 0; i < 100; i+= 10 ) {
(function(i){
setTimeout('test('+i+');', i);
})(i);
}
}
旁注:您应该将匿名函数传递给setTimeout
,而不是传递一个字符串(将被评估)。这种方式要快得多:
function test2() {
for( var i = 0; i < 100; i+= 10 ) {
(function(i){
setTimeout(function(){
test(i);
}, i);
})(i);
}
}