【问题标题】:Javascript: closure of loop?Javascript:循环关闭?
【发布时间】:2011-07-30 03:41:14
【问题描述】:

我想做以下事情:

for (var i = 0; i < 10; ++i) {
    createButton(x, y, function() { alert("button " + i + " pressed"); }
}

这个问题是我总是得到i的最终值,因为Javascript的闭包不是按值。
那么如何使用 javascript 做到这一点呢?

【问题讨论】:

标签: javascript closures anonymous-function


【解决方案1】:

如果您正在为使用 JavaScript 1.7 或更高版本的浏览器编写代码,一个解决方案是使用 let 关键字:

for(var i = 0; i < 10; ++i) {
    let index = i;
    createButton(x, y, function() { alert("button " + index + " pressed"); }
}

来自 MDC 文档中心:

let 关键字导致项目 用块创建的变量 级别范围,导致新的引用 为每次迭代创建 for 循环。这意味着一个 为每个捕获单独的变量 关闭,解决引起的问题 共享环境。

查看MDC Doc Center 了解传统方法(创建另一个闭包)。

【讨论】:

    【解决方案2】:
    for(var i = 0; i < 10; i++) {
        (function(i) {
            createButton(function() { alert("button " + i + " pressed"); });
        })(i);
    }
    

    请注意,JSLint 不喜欢这种模式。它抛出“不要在循环中创建函数。”。

    现场演示: http://jsfiddle.net/simevidas/ZKeXX/

    【讨论】:

    • 我比彼得更喜欢这个答案,因为它很干净。如果更多的浏览器支持let 关键字就好了。
    • @McStretch 我试图在 jsFiddle 中制作一个 let 演示,但我无法让它工作。见这里:jsfiddle.net/simevidas/ZKeXX/1 Firefox 4 抛出错误。
    • @Šime - 我刚刚看到这个问题:stackoverflow.com/questions/2356830/…,它说你必须明确告诉浏览器(现在只有 Firefox)你正在使用 1.7。这是一个更新的小提琴:jsfiddle.net/simevidas/ZKeXX/1。很蹩脚吧?在每个人都支持 1.7 或更高版本之前,显然不是一个真正好的解决方案,谁知道什么时候会发生。
    • @McStretch 我明白了。更新的演示(在 Firefox 中工作)在这里:jsfiddle.net/simevidas/ZKeXX/2 看来我们将无法使用 let 很长一段时间。即使 IE10 实现了它,我们也必须等到 IE9 退出市场(这可能不会在 2020 年之前发生)。
    【解决方案3】:

    通过执行另一个函数为闭包创建一个新作用域:

    for(var i = 0; i < 10; ++i) {
        createButton(x,y, function(value) { return function() { alert(...); }; }(i));
    }
    

    http://www.mennovanslooten.nl/blog/post/62

    【讨论】:

    • 1.您可能希望在 return 语句的末尾放置一个分号,以使代码更具可读性。 2. IIFE 通常用括号包裹。
    【解决方案4】:

    你需要把闭包放到一个单独的函数中。

    for(var dontUse = 0; dontUse < 10; ++dontUse) {
        (function(i) {
            createButton(x, y, function() { alert("button " + i + " pressed"); }
        })(dontUse);
    }
    

    此代码创建一个匿名函数,该函数将i 作为循环的每次迭代的参数。
    由于这个匿名函数在每次迭代中都有一个单独的i 参数,因此它可以解决问题。

    这相当于

    function createIndexedButton(i) {
        createButton(x, y, function() { alert("button " + i + " pressed"); }
    }
    
    for(var i = 0; i < 10; ++i) {
        createIndexedButton(i);
    }
    

    【讨论】:

      【解决方案5】:
      for(var i = 0; i < 10; ++i) {
          createButton(x, y, (function(n) {
              return function() {
                  alert("button " + n + " pressed");
              }
          }(i));
      }
      

      外部的匿名函数会被自动调用,并在其作用域内创建一个新的闭包,n,其中每次调用时都会采用i当前值。 p>

      【讨论】:

        猜你喜欢
        • 2016-08-26
        • 1970-01-01
        • 2017-02-19
        • 2012-11-18
        • 1970-01-01
        • 2015-04-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多