简体   繁体   English

在JavaScript中循环创建闭包

[英]Creating closures in a loop in JavaScript

I have this scenario: 我有这种情况:

<html>
<head>
<script type="text/javascript" src="jquery-1.4.4.js"></script>
<script type="text/javascript">
var actions = {
    'view' : function(){alert("view");},
    'history': function(){alert("history");},
    'renewal': function(){alert("renewal");}
}
for(var action in actions){
    $('.' + action).live('click', function(e){
        e.preventDefault();
        if(actions[action])
            actions[action]();
    });
}
</script>
</head>
<body>
    <a class="view" href="#">view</a>
    <a class="history" href="#">history</a>
    <a class="renewal" href="#">renewal</a>
</body>
</html>

I think a closure is created, since clicking a link always alerts "renewal" and I am not able to fix it. 我认为创建了一个闭包,因为点击链接总是提醒“续订”,我无法修复它。

Why dont you try using the classname in the click event? 为什么不尝试在click事件中使用classname?

I'm no jQuery expert, but something like this: 我不是jQuery专家,但是这样的话:

$('.' + action).live('click', function(e)
{
 e.preventDefault();
 if(actions[this.className])
   actions[this.className]();
});

It is indeed. 这的确是。 You can replace 你可以替换

for(var action in actions){
    $('.' + action).live('click', function(e){
        e.preventDefault();
        if(actions[action])
            actions[action]();
    });
}

with

for(var action in actions){
    $('.' + action).live('click', function(e){
        e.preventDefault();
        var currentAction = $(e.target).attr('class');
        if(actions[currentAction])
            actions[currentAction]();
    });
}

By the way, the problem is not that there is a closure. 顺便说一句,问题不在于是否存在关闭。 Indeed, if there was not a closure, the value of the variable action would not be rembered at all! 实际上,如果没有闭包,变量action的值根本就不会被记住! The problem is that all the functions in the loop refer to the same variable action , that at the end of the loop will have the value renewal . 问题是循环中的所有函数都引用相同的变量action ,在循环结束时它将具有值renewal

There are better ways of doing this, but to make your solution work: 有更好的方法可以做到这一点,但要使解决方案有效:

for(var action in actions){
    (function(myAction){
        $('.' + myAction).live('click', function(e){
            e.preventDefault();
            if(actions[myAction])
                actions[myAction]();
        });
    })(action);
}

You are going to find out that live is not going to cancel the default action, You are going to want to use delegate 您将发现实时不会取消默认操作,您将要使用委托

That's not what happens. 这不是发生的事情。 Instead, your event handler function references the action variable, which will always have the value 'renewal', since that 's the last item in the list after the loop is done. 相反,您的事件处理函数引用了action变量,该变量将始终具有值“renewal”,因为这是循环完成后列表中的最后一项。 The best way to go about it is to replace the loop with something like that: 最好的方法是用这样的东西替换循环:

for(var action in actions) {
    $('.' + action).live('click', function(e){
        e.preventDefault();
        var action = $(e.currentTarget).attr('class');
        if(actions[action]) actions[action]();
   });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM