首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript闭包未使用正确的值

Javascript闭包未使用正确的值
EN

Stack Overflow用户
提问于 2013-06-05 16:53:52
回答 1查看 92关注 0票数 0

我对闭包的了解还远远没有达到高级水平,但据我所知,定义的匿名函数在引用定义在该函数的同一范围内的局部变量时,会保留该变量的值,而不管稍后会对该变量产生什么影响。

这让我相信,在这段代码中,当每个表单域触发onblur时发出警报的值应该是不同的(分别是goHandle和go2Handle ):

代码语言:javascript
复制
 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,第二个值发出警报,建议闭包根本不是闭包,而只是使用变量的当前值。

您可以在此小提琴中观察到此行为:

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

有人能解释一下我在闭包方面做错了什么或误解了什么吗?以及为什么这不是我所期望的那样。非常感谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-06-05 16:58:11

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

实际上,变量fieldMethod的作用域扩展到for循环之外,就好像您在函数的顶部声明了它(这称为提升)。因此,当您为事件处理程序创建闭包时,所有这些事件处理程序都绑定到同一个变量。当处理程序被调用时,该变量的计算结果与上一次循环迭代期间的值相同--对于所有处理程序。

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

代码语言:javascript
复制
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);
    }
}

请注意,我们可以使用fieldMethod而不是methodName作为中间函数参数的名称(这将对外部作用域隐藏fieldMethod ),但我使用了另一个名称以避免混淆。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16935519

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档