I would like to do the something along the following:
for (var i = 0; i < 10; ++i) {
createButton(x, y, function() { alert("button " + i + " pressed"); }
}
The problem with this is that I always get the final value of i because Javascript's closure is not by-value.
So how can I do this with javascript?
-
You could edit createButton, allowing it to have another argument passed, that is, i. This way you can store i in your createButton function and use it.user657496– user6574962011年04月05日 16:55:09 +00:00Commented Apr 5, 2011 at 16:55
-
possible duplicate of Javascript closure inside loops - simple practical examplerds– rds2013年01月17日 17:53:41 +00:00Commented Jan 17, 2013 at 17:53
5 Answers 5
One solution, if you're coding for a browser that uses JavaScript 1.7 or higher, is to use the let keyword:
for(var i = 0; i < 10; ++i) {
let index = i;
createButton(x, y, function() { alert("button " + index + " pressed"); }
}
From the MDC Doc Center:
The let keyword causes the item variable to be created with block level scope, causing a new reference to be created for each iteration of the for loop. This means that a separate variable is captured for each closure, solving the problem caused by the shared environment.
Check out the MDC Doc Center for the traditional approach (creating another closure).
Comments
for(var i = 0; i < 10; i++) {
(function(i) {
createButton(function() { alert("button " + i + " pressed"); });
})(i);
}
Note that JSLint doesn't like this pattern. It throws "Don't make functions within a loop.".
Live demo: http://jsfiddle.net/simevidas/ZKeXX/
4 Comments
let keyword though.let demo in jsFiddle, but I couldn't make it work. See here: jsfiddle.net/simevidas/ZKeXX/1 Firefox 4 throws an error.let for a long time. Even if IE10 implements it, we'd have to wait until IE9 exits the market (and that may not happen before 2020).Create a new scope for the closure by executing another function:
for(var i = 0; i < 10; ++i) {
createButton(x,y, function(value) { return function() { alert(...); }; }(i));
}
1 Comment
You need to put the closure into a separate function.
for(var dontUse = 0; dontUse < 10; ++dontUse) {
(function(i) {
createButton(x, y, function() { alert("button " + i + " pressed"); }
})(dontUse);
}
Thise code creates an anonymous function that takes i as a parameter for each iteration of the loop.
Since this anonymous function has a separate i parameter for each iteration, it fixes the problem.
This is equivalent to
function createIndexedButton(i) {
createButton(x, y, function() { alert("button " + i + " pressed"); }
}
for(var i = 0; i < 10; ++i) {
createIndexedButton(i);
}
Comments
for(var i = 0; i < 10; ++i) {
createButton(x, y, (function(n) {
return function() {
alert("button " + n + " pressed");
}
}(i));
}
The anonymous function on the outside is automatically invoked and creates a new closure with n in its scope, where that takes the then current value of i each time it's invoked.
Comments
Explore related questions
See similar questions with these tags.