问题
I'm trying to use setTimeout to execute an anonymous function that I pass information into and I'm having trouble. This (hard-coded version) would work just fine:
setTimeout(function(){alert("hello");},1000);
setTimeout(function(){alert("world");},2000);
But I'm trying to take the hello and world from an array and pass them into the function without (a) using global variables, and (2) using eval. I know how I could do it using globals or eval, but how can I do it without. Here is what I'd like to do (but I know it won't work):
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout( function(){alert(strings[i]);}, delay);
delay += 1000;
}
Of course strings[i] will be out of context. How can I pass strings[i] into that anonymous function without eval or globals?
回答1:
This is the very frequently repeated "how do I use a loop variable in a closure" problem.
The canonical solution is to call a function which returns a function that's bound to the current value of the loop variable:
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout(
(function(s) {
return function() {
alert(s);
}
})(strings[i]), delay);
delay += 1000;
}
The outer definition function(s) { ... }
creates a new scope where s
is bound to the current value of the supplied parameter - i.e. strings[i]
- where it's available to the inner scope.
回答2:
Just add a scope around the setTimeout call:
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
(function(s){
setTimeout( function(){alert(s);}, delay);
})(strings[i]);
delay += 1000;
}
回答3:
You could write a separate function to set up the timeout:
function doTimer(str, delay) {
setTimeout(function() { alert(str); }, delay);
}
Then just call that from the loop:
var delay = 1000;
for(var i=0;i<strings.length;i++) {
doTimer(strings[i], delay);
delay += 1000;
}
回答4:
Although not as backward compatible as some of the other answers, thought I'd throw up another option.. this time using bind()!
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout(alert.bind(this, strings[i]), delay);
delay += 1000;
}
View demo of it in action
回答5:
var strings = [ "hello", "world" ];
var delay = 1000;
for(var i=0;i<strings.length;i++) {
setTimeout( new Function('alert(strings[i]);'), delay);
delay += 1000;
}
来源:https://stackoverflow.com/questions/6425062/passing-functions-to-settimeout-in-a-loop-always-the-last-value