简体   繁体   中英

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?

I'm no jQuery expert, but something like this:

$('.' + 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! 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 .

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. 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]();
   });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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