Javascript 闭包未使用正确的值

标签 javascript closures var

我对闭包的了解还远未达到高级水平,但据我了解,定义的匿名函数在引用在该函数的同一作用域内定义的局部变量时,会保留该变量的值,无论可能发生什么稍后影响该变量。

这让我相信,在这段代码中,每个表单字段触发其 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,第二个值都会发出警报,表明闭包根本不是闭包,而只是使用变量的当前值。

您可以在此 fiddle 中观察此行为:

http://jsfiddle.net/HpZ39/1/

有人可以解释一下我对关闭做错了什么或误解了什么吗?以及为什么这没有按我预期的方式工作。非常感谢。

最佳答案

这是因为你在循环中创建闭包,而 JS 变量具有函数作用域。

变量 fieldMethod 的作用域实际上延伸到 for 循环之外,就好像您已在函数顶部声明它一样(这称为吊装)。因此,当您为事件处理程序创建闭包时,所有闭包都绑定(bind)到同一个变量。当调用处理程序时,该变量将计算为最后一次循环迭代期间的值 - 对于所有处理程序。

解决方案:由于问题是变量作用域,并且由于仅为函数创建新作用域,因此插入一个额外的函数:

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来自外部范围),但我使用了另一个名称以避免造成混淆。

关于Javascript 闭包未使用正确的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16935519/

相关文章:

javascript - Ember : set value of property on text field

通过 href 调用 javascript 函数?

closures - 在多个闭包之一中捕获相同的变量

javascript - 随机访客看到图像

arrays - 在 swift 中将 var 声明为一个组

javascript - 使用 YouTube API v3 获取视频的完整描述

javascript - 使用正则表达式在 Javascript 中形成一个没有前导零的数字

javascript - 为什么 ind = index1() || 的值不是索引2();其中index1() = undefined 且index2() = 0 等于0 但未定义?

objective-c - Objective-c 中的 Smalltalk block ?

Linux bash 脚本 : share variable among terminal windows