jquery and javascript's closure

2019-07-24 11:46发布

问题:

I am having the code below and javascript's closure together with anonymous functions are giving me a headache.

for (var i = 0, len = sites.length ; i < len ; i++)
{
  $("#thumb"+i).click(function() { $("#shader").show(); $("#thumbInfo"+i).show(); alert("#thumbInfo"+i); });
  $("#thumbInfo"+i+" .xbutton").click(function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); });
}

Due to closure, i is always 5 (the sites array has 5 elements), so all the click handlers refer to the same id.

Any workaround?

回答1:

You could always loop with jQuery's each().

$.each(sites, function(i) {
  $("#thumb"+i).click(function() { $("#shader").show(); $("#thumbInfo"+i).show(); alert("#thumbInfo"+i); });
  $("#thumbInfo"+i+" .xbutton").click(function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); });
});


回答2:

use a closure in your for iteration:

for (var i = 0, len = sites.length ; i < len ; i++)
{
    (function(i) {
        $("#thumb"+i).click(function() {
            $("#shader").show(); 
            $("#thumbInfo"+i).show(); 
            alert("#thumbInfo"+i); 
        });
        $("#thumbInfo"+i+" .xbutton").click(function() { 
            $("#shader").hide(); 
            $("#thumbInfo"+i).hide(); 
        });
    }(i));
}


回答3:

Place a function returning a function and parameterized by i outside the loop. JSLint will encourage you to do this anyway, and some might find it more readable to boot.

function make_fn1(i) {
    return function() { $("#shader").show(); $("#thumbInfo"+i).show(); };
}
function make_fn2(i) {
    return function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); };
}
for (var i = 0; i < sites.length ; i++)
{
    $("#thumb"+i).click(make_fn1(i));
    $("#thumbInfo"+i+" .xbutton").click(make_fn2(i));
}

However, this could be cleaned up in other ways. For starters, as long as you're using jQuery, $("#shader, #thumbInfo"+i).show(); is more concise. Furthermore, in the current code the notion that the two functions either hide or show the same two elements is not factored out, so could be

function make_fn (i,showhide) {
    return function() { $("#shader, #thumbInfo"+i)[showhide]() };
}
for (var i = 0; i < sites.length ; i++)
{
    $("#thumb"+i).click(make_fn(i,'show'));
    $("#thumbInfo"+i+" .xbutton").click(make_fn(i,'hide'));
}


回答4:

var len = sites.length ;
for (var i = 0; i < len ; i++)
    {
      $("#thumb"+i).click(function() { $("#shader").show(); $("#thumbInfo"+i).show(); alert("#thumbInfo"+i); });
      $("#thumbInfo"+i+" .xbutton").click(function() { $("#shader").hide(); $("#thumbInfo"+i).hide(); });
    }

you might have been assigning 5 to i;