在for循环中创建闭包 – 我这样做了吗?

我很遗憾。 在这里非常密集,但我无法弄清楚下面的代码到底发生了什么。

我想要做的是将两个独立的处理程序附加到字段的change事件中。 每个处理程序都是通过循环遍历数组并使用数组中的项来设置的,以便在运行时实现处理程序的输出 – 希望在查看示例代码时变得清晰。

代码如下:

$(document).ready( function () { // // Create some test input fields on the page... // $('
').insertAfter($('body > *:last')); $('').insertAfter($('body > *:last')); $('').insertAfter($('body > *:last')); // // The problematic part - for me at least... // var arr = new Array(1, 2); for (var a in arr) { // Using Chrome console here for logging console.log("## " + a); $('#t0').change(function () { console.log(">> " + a) }); } });

因此,当我在第一个字段中添加值时,我期望发生的事情是从控制台内部(在Chrome中运行这些示例):

 ## 0 ## 1 >> 1 >> 2 

我得到的是:

 ## 0 ## 1 >> 1 >> 1 

我原以为传递给处理程序的函数会形成一个关于a的值的闭包,我最终会将两个函数绑定到处理程序,其中一个函数的值为1 ,另一个函数的值为2

想法?

干杯 – 克里斯

这里有两个大错:

首先, for (a in x)不像你期望的那样工作:它迭代对象属性,而不是数组元素。

另一个错误是函数被调用时的变化。 实现所需function的好方法是这样的:

 for(var a=0; a 

要查看如果不创建闭包, for循环会发生什么,请参阅:

 var arr = [1,2,3]; var functions = []; for(var a=0; a 

现在所有函数都将记录3 ,这是数组中最后一个元素的索引+ 1( arr[0] == 1, arr[1] == 2, arr[2] == 3 )。 会发生的是for循环在每次迭代时创建这些函数,但是在循环结束执行它们,当a == arr.length

而不是“for”循环,尝试jQuery 自己的工具 。

  $(arr).each(function(a) { console.log("## " + a); $('#t0').change(function () { console.log(">> " + a) }); }); 

这按预期工作。

您的代码不起作用的原因是闭包使用其变量的最新值。 也就是说,如果你创建一个等于1的闭包,然后当a等于2时创建另一个闭包,两个闭包都将使用最后一个值,2。这无疑是令人困惑的,但这就是它的工作原理。

你必须做这样的事情:

 for (var a in arr) { (function (a) { // thanks to closure variable a is local here $('#t0').change(function () { console.log(">> " + a); }); }(a)); } 

或者像这样:

 for (var a in arr) { $('#t0').change((function (a) { return function () { // returned function has access to local variable a from // outer function console.log(">> " + a); }; }(a)); } 

诀窍是将变量a放在比循环更深的范围内。 为了更容易阅读上面两个片段,可以写成:

 for (var a in arr) { (function (inner_a) { // thanks to closure variable a is local here $('#t0').change(function () { console.log(">> " + inner_a); }); }(a)); } for (var a in arr) { $('#t0').change((function (inner_a) { return function () { // returned function has access to local variable a from // outer function console.log(">> " + inner_a); }; }(a)); } 

BTW。 除非你通过对象属性进行交互,否则最好使用classic for(var i …)而不是for .. in循环。 并且$(’#t0’)应该被缓存:

 var cachedEl = $('#t0'); for (var a=0; a < arr.length; a++) { (function (inner_a) { // thanks to closure variable a is local here cachedEl.change(function () { console.log(">> " + inner_a); }); }(a)); } // or for (var a=0; a < arr.length; a++) { cachedEl.change((function (inner_a) { return function () { // returned function has access to local variable a from // outer function console.log(">> " + inner_a); }; }(a)); }