Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access outside variable in loop from Javascript closure [duplicate]

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?

like image 743
Bart van Heukelom Avatar asked Aug 26 '09 00:08

Bart van Heukelom


People also ask

How do you access variable outside loop?

SOLUTION: What you have to do to use a variable outside a loop, is to declare it before the loop begins, you don't have to initialize the variable before, but you have to initialize it before you try to use it for anything.

What is the closure in JavaScript can access variables?

This is called a JavaScript closure. It makes it possible for a function to have "private" variables. The counter is protected by the scope of the anonymous function, and can only be changed using the add function. A closure is a function having access to the parent scope, even after the parent function has closed.

Is closure unique to JavaScript?

Closures are a very powerful yet underused feature unique to of JavaScript (and other ECMAScript languages). They essentially provide your code with private variables that other scripts can't access.

What is Clouser in JavaScript?

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.


1 Answers

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);   }); }); 
like image 173
gnarf Avatar answered Sep 24 '22 23:09

gnarf