for循环中的闭包

Rob*_*Rob 12 javascript jquery closures loops

循环中的闭包导致我出现问题.我想我必须创建另一个函数来返回一个函数来解决问题,但我无法使用我的jQuery代码.

以下是简化形式的基本问题:

function foo(val) {
  alert(val);
}

for (var i = 0; i < 3; i++) {
  $('#button'+i).click(function(){
    foo(i);
  });
}
Run Code Online (Sandbox Code Playgroud)

自然地点击三个按钮中的任何一个都会发出警告说3.我想要的功能是点击按钮1将发出警告说1,按钮2会说2等.

我该怎么做呢?

And*_*y E 10

请参阅绑定方法.

$('#button'+i).bind('click', {button: i}, function(event) {
  foo(event.data.button);
});
Run Code Online (Sandbox Code Playgroud)

来自文档:

可选的eventData参数不常用.提供时,此参数允许我们将其他信息传递给处理程序.使用此参数的一个方便是解决由闭包引起的问题


Mir*_*anu 6

试试这段代码:

function foo(val) {
  alert(val);
}

var funMaker = function(k) {
  return function() {
    foo(k);
  };
};

for (var i = 0; i < 3; i++) {
  $('#button'+i).click(funMaker(i));
}
Run Code Online (Sandbox Code Playgroud)

这里有一些重点:

  • JavaScript是功能范围的.如果你想要一个新的("更深的")范围,你需要创建一个函数来保存它.
  • 这个解决方案是特定于Javascript的,它可以使用或不使用jQuery.
  • 该解决方案的工作原理是因为每个值都i被复制到一个新的作用域中k,并且返回的函数funMaker关闭k(在循环中不会改变),而不是围绕i(确实如此).
  • 您的代码不起作用,因为您传递给的click函数不"拥有"它i,它关闭i它的创建者,并且i在循环中发生变化.
  • 该示例可以使用funMaker内联编写,但我通常使用这样的帮助函数来使事情更清晰.
  • funMakeris 的论证是k,但没有区别,它本来i没有任何问题,因为它存在于函数的范围内funMaker.
  • 关于"环境"评估模型的最清楚的解释是在Sussman&Abelson的"计算机程序的结构和解释"中找到的(http://mitpress.mit.edu/sicp/在线提供全文,而不是简单的阅读) - 见3.2节.由于JavaScript实际上是带有C语法的Scheme,因此该解释是可以的.

编辑:修正了一些标点符号.


Vin*_*ert 5

@Andy解决方案是最好的.但您也可以使用Javascript作用域来帮助您保存闭包中的值.

您可以通过执行匿名函数在循环体中创建新范围来实现.

for (var i = 0; i < 3; i++) {
  (function(){
    var index = i; 
    $('#button'+index).click(function(){
      foo(index);
    });
  })();
}
Run Code Online (Sandbox Code Playgroud)

由于循环体在每次迭代时都是一个新的范围,因此索引变量在每次迭代时都会以正确的值复制.