我对闭包的了解远非高级,但我的理解是,当引用在该函数的同一范围内定义的局部变量时,定义的匿名函数保存该变量的值,尽管可能稍后影响所述变量。
这让我相信,在这段代码中,当每个表单字段触发它的onblur时提醒的值应该是不同的(分别是goHandle和go2Handle):
var formBean = {
"formString": "Demo",
"formFields":[
{
"name":"go",
"id":"go",
"validationString":"myTest"
},
{
"name":"go2",
"id":"go2",
"validationString":"myTest2"
}
]
};
window.onload = function()
{
for(var i=0;i<formBean.formFields.length;i++) {
var field = formBean.formFields[i];
var fieldMethod = field.name + "Handle";
document.getElementById(field.id).onblur = function() {
alert(fieldMethod);
};
}
}
<input type="text" id="go" />
<input type="text" id="go2" />
然而,发生的事情是,无论你离开哪个字段,从而触发onblur,第二个值警告,建议闭包不是闭包,而只是使用变量的当前值。
你可以在这个小提琴中观察到这种行为:
有人可以解释一下我做错了什么或误解了关闭?为什么这不符合我的预期。非常感谢你。
答案 0 :(得分:2)
这是因为你在循环中创建闭包,而JS变量有函数作用域。
变量fieldMethod
的范围实际上扩展到for
循环之外,就好像你已经在函数的顶部声明它(这称为提升) 。因此,当您为事件处理程序创建闭包时,所有闭包都绑定到同一个变量。当调用处理程序时,变量的计算结果是在上一次循环迭代期间的变量 - 对于所有处理程序。
解决方案:由于问题是变量范围,并且由于仅为函数创建了新范围,因此插入一个额外的函数:
window.onload = function()
{
for(var i=0;i<formBean.formFields.length;i++) {
var field = formBean.formFields[i];
var fieldMethod = field.name + "Handle";
// Defining an anon function and calling it on the spot, passing the
// current value of fieldMethod. This results in each handler creating
// closure to a different variable.
(function(methodName) {
document.getElementById(field.id).onblur = function() {
alert(methodName);
};
})(fieldMethod);
}
}
<强> Updated fiddle 强>
请注意,我们可以使用fieldMethod
而不是methodName
作为中间函数参数的名称就好了(这会将fieldMethod
隐藏在外部范围内),但我使用过另一个名字,以避免造成混淆。