似乎我并不像我想的那样理解javascript回调。
在下面的例子中,我认为setTimeout中每个函数副本都会引用它自己的变量“index”。因此,运行该示例应产生以下警报:“zero”“one”“two”。
var array = ["zero", "one", "two"];
var out = "";
for(var i = 0; i < 3; i++){
var index = i;
setTimeout( function(){alert(array[index])}, 1 );
}
然而,似乎只有索引变量的一个副本,并且回调函数的所有副本都指向同一个变量,给我以下警告:“two”“two”“two”。
java中的以下analagous(我认为)示例按预期打印“零”“一”“两”。
import java.util.ArrayList;
import java.util.List;
public class CallBacks {
public static void main(String[] args) {
String[] array = {"zero", "one", "two"};
List<Callback> callBacks = new ArrayList<Callback>();
for(int i = 0; i<3; i++){
final String print = array[i];
callBacks.add(
new Callback(){
public void execute(){
System.out.println(print);
}
}
);
}
for(Callback cb : callBacks){
cb.execute();
}
}
private interface Callback{
public void execute();
}
}
任何人都可以向我解释为什么js例子不起作用,也许可以比较两个例子中发生的事情?
答案 0 :(得分:1)
index
随着循环的每次迭代而改变。你想要的是将index
放入一个不受循环影响的闭包中:
var array = ["zero", "one", "two"];
var out = "";
for(var i = 0; i < 3; i++) {
(function(index) {
setTimeout( function(){alert(array[index])}, 1 );
})(i)
}
答案 1 :(得分:1)
在javascript中,for循环没有它自己的作用域 - 所以你在循环中创建的var与在它之外定义的var没有区别。
答案 2 :(得分:0)
Private Members In JavaScript是我最喜欢的闭包参考。它被编写为在JS对象中提供私有变量的一个秘诀(可能很有用,也许不是)但是在这个过程中会对闭包的工作原理进行一次很好的介绍,特别是在JS中。
The comp.lang.javascript FAQ也有一个关于闭包的有价值的部分。
闭包可能会令人困惑,所以我整理了一份working example of the shortest useful closure I've come across,,这是Rhino书中的内容。
哦,我还没有足够的代表发表评论:)但我在上面看到了你的问题,为什么你有时必须在括号内添加括号。只有在调用内联匿名函数时才需要这样做。例如,这里需要括号:
(function (arg) {alert(arg);})('hi world');
因为您正在创建一个函数,然后立即调用它。但是在通常的情况下,你只需要声明一个命名函数供以后使用,这些内容是不必要的。