Alex Rivera | Logout

Access outside variable in loop from Javascript closure

Asked 2009-08-26T00:36:11.873
36

See:

for (var i in this.items) {
    var item = this.items[i];
    $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
    $("#showcasebutton_"+item.id).click(function() {
        alert(item.id);
        self.switchto(item.id);
    });
}

The problem is that the alerted item.id is always the id of the last item in the array (this.items). How to solve?

Edit
Report

1 Answer

40

The problem you have here is that the variable item changes with each loop. When you are referencing item at some later point, the last value it held is used. You can use a technique called a closure (essentially a function that returns a function) to quickly scope the variable differently.

    for (var i in this.items) {
            var item = this.items[i];
            $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
            $("#showcasebutton_"+item.id).click( 
                // create an anonymous function that will scope "item"
                (function(item) {
                   // that returns our function 
                   return function() {
                    alert(item.id);
                    self.switchto(item.id);
                   };
                })(item) // immediately call it with "item"
            );
    }

A side note - I see that you have jQuery here. It has a helper function $.each() that can be used with arrays, and can be a shortcut for simple for/each loops. Because of the way the scoping works in this call - you wont need to use a closure because "item" is already the parameter of the function when it was called, not stored in a var in the parent function's scope, like was true in your example.

$.each(this.items,function(i, item) {
  $("#showcasenav").append("<li id=\"showcasebutton_"+item.id+"\"><img src=\"/images/showcase/icon-"+item.id+".png\" /></li>");
  $("#showcasebutton_"+item.id).click(function() {
    alert(item.id);
    self.switchto(item.id);
  });
});
answered 2009-08-26T00:46:10.367

Your Answer