java和javascript回调比较

时间:2009-01-15 15:12:42

标签: java javascript closures callback

似乎我并不像我想的那样理解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例子不起作用,也许可以比较两个例子中发生的事情?

3 个答案:

答案 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');

因为您正在创建一个函数,然后立即调用它。但是在通常的情况下,你只需要声明一个命名函数供以后使用,这些内容是不必要的。