【问题标题】:java and javascript callbacks comparedjava和javascript回调比较
【发布时间】:2010-10-01 14:50:03
【问题描述】:

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

【问题讨论】:

标签: java javascript closures callback


【解决方案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)
}

【讨论】:

  • 谢谢。我想我认为 for 循环的每次迭代都会创建一个闭包。
  • 嗯,是的,从技术上讲,我忽略了那部分。 有一个围绕索引的闭包。但它是在传递给 setTimeout 的函数的外部范围内声明的。 “闭包”!=“不变的变量”。
  • 酷。还有一个问题:为什么函数声明需要用括号括起来?
  • @morgancodes:这只是惯例;此外,在某些情况下,解析器可能会产生不正确的结果
  • javascript 中的闭包(对函数外部变量的引用)保留它们的关联...如果您在循环结束后调用的函数中引用循环变量,则在函数调用中您将获得循环后的那个变量。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    闭包可能会让人困惑,所以我整理了一个working example of the shortest useful closure I've come across,,它在 Rhino 书中。

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 2014-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多