在for循环中创建闭包——我这样做对吗
Creating closures within a for loop - am I doing this right?
我有问题。这里非常密集,但我无法弄清楚下面代码中到底发生了什么。
我要做的是将两个独立的处理程序附加到字段的更改事件。每个处理程序都是通过在数组上循环设置的,并在处理程序运行时使用数组中的项来影响处理程序的输出——希望在查看示例代码时会变得清楚。
代码如下:
$(document).ready( function () {
//
// Create some test input fields on the page...
//
$('<br />').insertAfter($('body > *:last'));
$('<input type="text" name="t0" id="t0" value="" />').insertAfter($('body > *:last'));
$('<input type="text" name="t1" id="t1" value="" />').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
的值上形成一个闭包,最终会有两个函数绑定到处理程序,一个是a
的值为1
,另一个是a
的值为2
。
想法?
Cheers-kris
这里有两个大错误:
首先,for (a in x)
并不像您期望的那样工作:它在对象属性上迭代,而不是在数组元素上迭代。
另一个错误是a
在函数被调用时发生了变化。实现所需功能的一个好方法如下:
for(var a=0; a<arr.length; a++) {
(function(a) {
// now you can use "a"
})(arr[a]);
}
要查看如果不创建闭包,for
循环会发生什么,请参阅以下内容:
var arr = [1,2,3];
var functions = [];
for(var a=0; a<arr.length; a++) {
functions.push(function() {
console.log(a);
})
}
// now execute all the functions
for(var i=0; i<functions.length; i++) {
functions[i]();
}
现在,所有函数都将记录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)
});
});
这符合预期。
代码不起作用的原因是闭包使用了其变量的最新值。也就是说,如果创建一个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循环更深的范围中。为了更容易阅读,上面的两个片段可以写成:
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));
}
顺便说一句。最好使用classic for(var i…)而不是for。。循环中,除非您正在交互对象属性。并且$('#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));
}
- 在underscorejs模板中使用闭包
- setTimeout可以与闭包内的函数一起使用吗
- 附加到原型属性的Do函数没有闭包
- 页面在我的javascript执行后重新加载,我不希望它这样做
- 使用闭包共享构造函数参数
- 使用Google闭包编译器包含一个Ecmascript 6类
- 从js引擎的角度来看闭包和构造函数是如何工作的
- for循环中的JavaScript闭包
- Javascript闭包-如何防止内存泄漏
- 子类访问父类's闭包变量
- 闭包如何具体化数据封装
- Javascript.闭包和dynamic'这'实际上具有约束力
- 构造函数函数闭包变量
- 闭包js框架-将ArrayBuffer转换为字符串
- 如何在Angularjs中重构闭包中的重复代码
- 如何告诉闭包javascript编译器不要混淆webkitAudioContext的方法名称
- 闭包中的本地变量从外部更改.这是一个javascript错误,或者我做错了什么
- 闭包 - 为什么这条线是这样编码的
- 在for循环中创建闭包——我这样做对吗
- 是否可以将匿名函数标记为“实时代码”?这样闭包编译器就不会删除它