Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Closures are one of those things which has been discussed a lot on SO, but this situation pops up a lot for me and I'm always left scratching my head what to do.

var funcs = {};
for (var i = 0; i < 3; i++) {          // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + i); // each should log its value.
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

It outputs this:

My value: 3
My value: 3
My value: 3

Whereas I'd like it to output:

My value: 0
My value: 1
My value: 2

What's the solution to this basic problem?

share|improve this question

10 Answers

up vote 160 down vote accepted

Well, the problem is that the variable i, within each of your anonymous functions, is bound to the same variable outside of the function.

What you want to do is bind the variable within each function to a separate, unchanging value outside of the function:

var funcs = [];

function createfunc(i) {
    return function() { console.log("My value: " + i); };
}

for (var i = 0; i < 3; i++) {
    funcs[i] = createfunc(i);
}

for (var j = 0; j < 3; j++) {
    funcs[j]();                        // and now let's run each one to see
}

Since there is no block scope in JavaScript - only function scope - by wrapping the function creation in a new function, you ensure that the value of "i" remains as you intended.

share|improve this answer
Ah - same as apphacker's solution - but slightly more verbose... – harto Apr 15 '09 at 6:20
10  
And less confusing – Darren Clark Apr 15 '09 at 6:51
Very nice explanation. Saved my day! – Raj May 21 '10 at 9:44

Try:

var funcs = [];

for (var i = 0; i < 3; i++) {          
    funcs[i] = (function(index) {   
        return function() {          
            console.log("My value: " + index);
        } 
    })(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        
}
share|improve this answer
thanks for this, app. This is the solution I went with in my own code, but I'm accepting the harto's since it's a little clearer, plus he could use the rep :p – nickf Apr 16 '09 at 0:37
Thank you! I always ended up doing something similar to the accepted solution, precisely when I wanted to avoid declaring another top-level function. This is perfect! – Daniel Magliola May 12 '09 at 1:13

What you need to understand is the scope of the variables in javascript is based on the function. This is an important difference than say c# where you have block scope, and just copying the variable to one inside the for will work.

Wrapping it in a function that evaluates returning the function like apphacker's answer will do the trick, as the variable now has the function scope.

There is also a let keyword instead of var, that would allow using the block scope rule. In that case defining a variable inside the for would do the trick. That said, the let keyword isn't a practical solution because of compatibility.

var funcs = {};
for (var i = 0; i < 3; i++) {
    let index = i;          //add this
    funcs[i] = function() {            
        console.log("My value: " + index); //change to the copy
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();                        
}
share|improve this answer
this doesn't work. "missing ; before statement -- let index = i;" – nickf Apr 15 '09 at 6:35
@nickf which browser? as I said, it has compatibility issues, with that I mean serious compatibility issues, like I don't think let is supported in IE. – eglasius Apr 15 '09 at 6:54
...nor firefox. We're talking about javascript right? – nickf Apr 16 '09 at 0:36
1  
@nickf yes, check this reference: developer.mozilla.org/En/New_in_JavaScript_1.7 ... check the let definitions section, there is an onclick example inside a loop – eglasius Apr 16 '09 at 2:55
1  
@nickf hmm, actually you have to explicitly specify the version: <script type="application/javascript;version=1.7"/> ... I haven't actually used it anywhere because of the IE restriction, it just isn't practical :( – eglasius Apr 16 '09 at 2:58
show 2 more comments

Another way of saying it is that the i in your function is bound at the time of executing the function, not the time of creating the function.

When you create the closure, i is a reference to the variable defined in the outside scope, not a copy of it as it was when you created the closure. It will be evaluated at the time of execution.

Most of the other answers provide ways to work around by creating another variable that won't change value on you.

Just thought I'd add an explanation for clarity. For a solution, personally I'd go with Harto's since it is the most self explanatory way of doing it from the answers here. Any of the code posted will work, but I'd opt for a closure factory over having to write a pile of comments to explain why I'm declaring a new variable(Freddy and 1800's) or have weird embedded closure syntax(apphacker).

share|improve this answer
+1 for the first line of your explanation – user1988876 Jun 18 at 7:23

Here's another variation on the technique, similar to Bjorn's (apphacker), which lets you assign the variable value inside the function rather than passing it as a parameter, which might be clearer sometimes:

for (var i = 0; i < 3; i++) {
    funcs[i] = (function() {
        var index = i;
        return function() {
            console.log("My value: " + index);
        }
    })();
}

Note that whatever technique you use, the index variable becomes a sort of static variable, bound to the returned copy of the inner function. I.e., changes to its value are preserved between calls. It can be very handy.

share|improve this answer

This describes the common mistake with using closures in JavaScript.

A function defines a new environment

Consider:

function makeCounter()
{
  var obj = {counter: 0};
  return {
    inc: function(){obj.counter ++;},
    get: function(){return obj.counter;}
  };
}

counter1 = makeCounter();
counter2 = makeCounter();

counter1.inc();

alert(counter1.get()); // returns 1
alert(counter2.get()); // returns 0

For each time makeCounter is invoked, {counter: 0} results in a new object being created. Also, a new copy of obj is created as well to reference the new object. Thus, counter1 and counter2 are independent of each other.

Closures in loops

Using a closure in a loop is tricky.

Consider:

var counters = [];

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = {
      inc: function(){obj.counter++;},
      get: function(){return obj.counter;}
    }; 
  }
}

makeCounters(2);

counters[0].inc();

alert(counters[0].get()); // returns 1
alert(counters[1].get()); // returns 1

Notice that counters[0] and counters[1] are not independent. In fact, they operate on the same obj!

This is because there is only one copy of obj shared across all iterations of the loop, perhaps for performance reasons. Even though {counter: 0} creates a new object in each iteration, the same copy of obj will just get updated with a reference to the newest object.

Solution is to use another helper function:

function makeHelper(obj)
{
  return {
    inc: function(){obj.counter++;},
    get: function(){return obj.counter;}
  }; 
}

function makeCounters(num)
{
  for (var i = 0; i < num; i++)
  {
    var obj = {counter: 0};
    counters[i] = makeHelper(obj);
  }
}

This works because local variables in the function scope directly, as well as function argument variables, are allocated new copies upon entry.

For a detailed discussion, please see JavaScript closure pitfalls and usage

share|improve this answer

With ES6 around the corner, note that the correct answer to this question will be changing. ES6 provides the let keyword for this exact circumstance. Instead of messing around with closures, we can just use let to set a loop scope variable like this:

var funcs = {};
for (var i = 0; i < 3; i++) {          
    let val = i;
    funcs[i] = function() {            
      console.log("My value: " + val); 
    };
}

val will then point to an object that is specific to that particular turn of the loop, and will return the correct value without the additional closure notation. This obviously significantly simplifies this problem.

Browser support is currently sketchy, but let is currently supported in the latest version of firefox (21.0) and Dev builds of chrome. You can see a working example here if you have a compatible browser: http://jsfiddle.net/ben336/rbU4t/2/

share|improve this answer

so the reason your original example did not work is that all the closures you created in the loop referenced the same frame. in effect having 3 methods on one object with only a single 'i' variable. they all printed out the same value

share|improve this answer

The value i inside the body of the closure is being bound to the same instance for each closure (that is, to the variable i which is the loop control variable for the for loop). This value is changing as you go through the loop. You need to figure out a way to make sure that it is bound to a different variable that is unique for each closure. The method shown by apphacker is one way, although possibly a little arcane.

var funcs = {};
for (var i = 0; i < 3; i++) { 
    var index = i;                     // let's create 3 functions
    funcs[i] = function() {            // and store them in funcs
        console.log("My value: " + index); // each should log its value.
    };
}

This method doesn't work - the reason being because var in javascript uses function scope as opposed to other algol derivatives which use block scope. You can use let as a slightly less portable alternative, but it looks like your best bet is to use a factory method to create the closures.

share|improve this answer
1  
no it doesn't work: they now all share the same scope on index and all output their value as "2". – nickf Apr 15 '09 at 6:25
that right, that won't work, check my answer on the why. – eglasius Apr 15 '09 at 6:27
ah yes delightful. I've updated my answer with further details – 1800 INFORMATION Apr 15 '09 at 8:22

You can make it by recursive function, like that

function hellowfunction(i){   

  var j=0;  //make our iterator

  (function onetick(){  
    if(j<i){           //checking state
      setTimeout(function(){ 
          console.log(j++);  //increment the value
          onetick();         //call function again
      },1000)          //Waiting one second for above function
    }
  })(); //Run function first time after creation
};


hellowfunction(4); // Turn it for 0..(sec)..1..2..3

improvement of this method is that you do not create a bunch of function with setTimeout at the beginning

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.