2

看来我并不像我想象的那样理解 javascript 回调。

在以下示例中,我认为 setTimeout 中的每个函数副本都将引用其自己的变量“index”副本。因此,运行该示例应产生以下警报:“零”“一”“二”。

var array = ["zero", "one", "two"];
var out = "";
for(var i = 0; i < 3; i++){
    var index = i;
    setTimeout(  function(){alert(array[index])},  1 );
}

但是,似乎索引变量只有一个副本,并且回调函数的所有副本都指向同一个变量,给我以下警报:“两个”“两个”“两个”。

java中的以下类似(我认为)示例按预期打印“零”“一”“二”。

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 示例不起作用,或许可以比较两个示例中发生的情况?

4

3 回答 3

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)
}
于 2009-01-15T15:17:36.533 回答
1

在 javascript 中,for 循环没有它自己的范围 - 所以您在循环内创建的 var 与在循环外定义的 var 没有什么不同。

于 2009-01-15T15:20:27.450 回答
0

JavaScript 中的私有成员是我最喜欢的关于闭包的参考。它被编写为在 JS 对象中提供私有变量的秘诀(可能有用,也可能没有),但在此过程中,它很好地介绍了闭包的一般工作原理,尤其是在 JS 中。

comp.lang.javascript FAQ也有一个关于闭包的有价值的部分。

闭包可能会令人困惑,所以我整理了一个我遇到的最短有用闭包的工作示例,它在 Rhino 书中。

哦,我还没有足够的代表发表评论 :) 但我在上面看到了你关于为什么有时必须在函数周围加上括号的问题。仅当您内联调用匿名函数时才需要这样做。例如这里需要括号:

(function (arg) {alert(arg);})('hi world');

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

于 2009-01-15T16:53:30.943 回答