Reputation: 14058
I was reading this website for notes on closure: blog.morrisjohns.com/javascript_closures_for_dummies.html
It had the following example:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
Their notes (correctly) point out:
The line result.push( function() {alert(item + ' ' + list[i])} adds a reference to an anonymous function three times to the result array. If you are not so familiar with anonymous functions think of it like: pointer = function() {alert(item + ' ' + list[i])}; result.push(pointer);
Note that when you run the example, "item3 undefined" is alerted three times! This is because just like previous examples, there is only one closure for the local variables for buildList. When the anonymous functions are called on the line fnlistj; they all use the same single closure, and they use the current value for i and item within that one closure (where i has a value of 3 because the loop had completed, and item has a value of 'item3').
Is there a "correct" way to get the "expected" behavior in javascript?
Thanks!
Upvotes: 0
Views: 1982
Reputation: 41832
Yes, you assign the value of i to a another variable so that variable can be part of the closure.
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push(function(cItem, index){
return function(){ alert(cItem + ' ' + list[index]); }
}(item, i));
}
return result;
}
The reason for this is that JavaScript does not have block scope, but a lexical scope that is capture by functions. To get around this problem, you create another function, as seen above, thereby capturing the variables into a new scope that will not be affected by the loop.
Upvotes: 1
Reputation: 522110
result.push((function (jtem, j) {
return function() { alert(jtem + ' ' + list[j]); }
})(item, i));
You create an anonymous function which introduces a new variable scope. You immediately execute that function, passing your variables, which become the new variables jtem
and j
in a new scope, hence the "connection" to item
and i
is "broken". You then return the actual function, which now uses different variables (you could keep the names i
and item
, I just changed them for illustrative purposes).
Upvotes: 3