By nickf


2009-04-15 06:06:20 8 Comments

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

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


The same problem occurs when the delay in running the function is caused by using event listeners:

var buttons = document.getElementsByTagName("button");
// let's create 3 functions
for (var i = 0; i < buttons.length; i++) {
  // as event listeners
  buttons[i].addEventListener("click", function() {
    // each should log its value.
    console.log("My value: " + i);
  });
}
<button>0</button>
<br />
<button>1</button>
<br />
<button>2</button>

… or asynchronous code, e.g. using Promises:

// Some async wait function
const wait = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms));

for (var i = 0; i < 3; i++) {
  // Log `i` as soon as each promise resolves.
  wait(i * 100).then(() => console.log(i));
}

What’s the solution to this basic problem?

30 comments

@Daryl 2014-05-03 03:42:57

Here's a simple solution that uses forEach (works back to IE9):

var funcs = [];
[0,1,2].forEach(function(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
}

Prints:

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

@Bimal Das 2018-01-16 13:16:44

forEach does not support IE8 or lower version !!!

@Daryl 2018-01-17 23:38:38

That's why I said "works back to IE9" ....

@Shivang Gupta 2019-05-02 11:57:47

Till ES5, This problem can only be solved using closure.

But now in ES6, we have block level scope variables. Changing var to let in first for loop will solve the problem.

var funcs = [];
for (let 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
}

@harto 2009-04-15 06:18:17

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

Classic solution: Closures

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++) {
  // and now let's run each one to see
  funcs[j]();
}

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.


2015 Solution: forEach

With the relatively widespread availability of the Array.prototype.forEach function (in 2015), it's worth noting that in those situations involving iteration primarily over an array of values, .forEach() provides a clean, natural way to get a distinct closure for every iteration. That is, assuming you've got some sort of array containing values (DOM references, objects, whatever), and the problem arises of setting up callbacks specific to each element, you can do this:

var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
  // ... code code code for this one element
  someAsynchronousFunction(arrayElement, function() {
    arrayElement.doSomething();
  });
});

The idea is that each invocation of the callback function used with the .forEach loop will be its own closure. The parameter passed in to that handler is the array element specific to that particular step of the iteration. If it's used in an asynchronous callback, it won't collide with any of the other callbacks established at other steps of the iteration.

If you happen to be working in jQuery, the $.each() function gives you a similar capability.


ES6 solution: let

ECMAScript 6 (ES6) introduces new let and const keywords that are scoped differently than var-based variables. For example, in a loop with a let-based index, each iteration through the loop will have a new value of i where each value is scoped inside the loop, so your code would work as you expect. There are many resources, but I'd recommend 2ality's block-scoping post as a great source of information.

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

Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let but get the above wrong (they don't create a new i each time, so all the functions above would log 3 like they would if we used var). Edge 14 finally gets it right.

@PCA 2013-08-17 13:08:08

That was a good explanation, i have been reading through closures, but not clearly understood how the i value is not unique as 1,2,3. But after reading your post, i understood that javascript does not have block scope and only have function scope. Thanks for the simple answer.

@アレックス 2014-03-28 03:45:40

isn't function createfunc(i) { return function() { console.log("My value: " + i); }; } still closure because it uses the variable i?

@cookie monster 2014-04-04 19:30:21

@Alex: Yes. All JavaScript functions create closures. The only question is the state of the closed-over variable that the function references. The solution creates a new variable scope upon invocation of createfunc that has both the i value at the time of invocation and a function that references that i. So each returned function (closure) is in its own scope closing over its own i.

@Wladimir Palant 2014-06-20 12:21:23

Unfortunately, this answer is outdated and nobody will see the correct answer at the bottom - using Function.bind() is definitely preferable by now, see stackoverflow.com/a/19323214/785541.

@cookie monster 2014-07-12 02:35:51

@Wladimir: Your suggestion that .bind() is "the correct answer" isn't right. They each have their own place. With .bind() you can't bind arguments without binding the this value. Also you get a copy of the i argument without the ability to mutate it between calls, which sometimes is needed. So they're quite different constructs, not to mention that .bind() implementations have been historically slow. Sure in the simple example either would work, but closures are an important concept to understand, and that's what the question was about.

@greenoldman 2014-11-21 07:14:51

@LoïcFaure-Lacroix, how let helps in capturing the values, and not references?

@Christian Landgren 2015-02-07 10:23:16

Please stop using these for-return function hacks, use [].forEach or [].map instead because they avoid reusing the same scope variables.

@user1106925 2015-06-29 16:31:47

@ChristianLandgren: That's only useful if you're iterating an Array. These techniques aren't "hacks". They're essential knowledge.

@Carsten Farving 2015-09-22 06:09:00

@ChristianLandgren For instance in asynchronous callbacks, you might need to use these techniques because you don't have an array to iterate over. NirmitSrivastava Mostly what works in the early years of javascript is still compliant to whatever used today.

@Christian Landgren 2015-09-22 07:15:55

@CarstenFarving When dealing with asynchronous callbacks it is essential that you keep a reference to a scoped variable since the parent value may be changed between the time you create a request until you get the response. If you don't have an array, just create one with [1,2,3].forEach((i) => doSomething(i))

@arnabkaycee 2015-11-26 10:12:08

This is a basic problem that 'var' variables face, i.e. they are function scoped instead of block scoped. 'var' variables undergo hoisting. This problem is overcome by 'let' statement introduced in ES6. See. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

@JSG 2016-04-18 20:16:01

The "let" method seems to work great for me being that it does work exactly how i intended the script to work before i stumbled upon closure issues. I needed to create the function on the go restoring previous functionality to onclick behavior. In a parent function vars are set and computed and passed through.

@Costa 2016-12-07 17:03:28

This isn't actually that complicated. The relevant question is from @アレックス: "Isn't function createfunc(i) { return function() { console.log("My value: " + i); }; } still closure because it uses the variable i?" The answer is, Yes, of course! Now you're getting it. When a function is declared is closes over the scope in which it was declared. createFunc(i) is a whole new closure, one level deeper. Remember how functions use the nearest variable reference? What's a bit confusing is that we used i as the argument for createFunc instead of n or some other random counter.

@nnnnnn 2016-12-12 03:01:02

Note that using let within the for loop's () doesn't work properly in IE (one workaround: add a let variable inside the {} block of the for, which does work properly in IE).

@Somnium 2017-02-13 12:11:33

Using let is best approach in new browsers, however it is more correct to add let inside for body, as @nnnnnn suggests, because for loop header has its own scope (however it works in non-IE browsers for some reason when it shouldn't).

@nnnnnn 2017-02-13 14:10:38

@Somnium - it's IE that implements it incorrectly. The other browsers do what the spec says.

@Pawel 2017-02-27 16:36:57

@WladimirPalant the answer you link to is a worse solution than this one. "bind" is good for setTimeout and callbacks but not for using it in a loop

@Wladimir Palant 2017-02-27 17:23:44

@Pawel: This question is about creating instances of a particular function bound to specific parameters - this is exactly what Function.bind() is good for. The loop merely demonstrates the principle, it's simply about binding variables that can change after the fact. In an actual loop you could use a let statement by now of course but support for it is only now becoming sufficient to be used unfortunately.

@Pawel 2017-02-28 15:01:27

@WladimirPalant bind primary function is to bind the context not attributes. Attributes are in addition to the context so bind in this case is an overkill. Compared to returning a function bind is 3 times slower in Chrome and 10 times slower in Firefox and Edge.

@mbomb007 2018-03-23 21:17:58

IE11 actually supports let correctly. See caniuse.com/#search=let

@JLRishe 2018-04-04 20:20:28

@mbomb007 No it doesn't. Try running the following in IE, Firefox, and Chrome. You will get different results: (function () { for(let a = 0; a < 10; a += 1) { setTimeout(function() { console.log(a); }, 100); } })()

@mbomb007 2018-04-04 21:27:51

@JLRishe Someone should tell caniuse.com to add note #4 to IE11 then

@JLRishe 2018-04-05 07:22:44

@mbomb007 Seems like it's a little different from #4 but I have submitted a PR to attempt to correct their data.

@Ben McCormick 2013-05-21 03:04:48

With ES6 now widely supported, the best answer to this question has changed. ES6 provides the let and const keywords 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 (let i = 0; i < 3; i++) {          
    funcs[i] = function() {            
      console.log("My value: " + i); 
    };
}

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.

const is similar to let with the additional restriction that the variable name can't be rebound to a new reference after initial assignment.

Browser support is now here for those targeting the latest versions of browsers. const/let are currently supported in the latest Firefox, Safari, Edge and Chrome. It also is supported in Node, and you can use it anywhere by taking advantage of build tools like Babel. You can see a working example here: http://jsfiddle.net/ben336/rbU4t/2/

Docs here:

Beware, though, that IE9-IE11 and Edge prior to Edge 14 support let but get the above wrong (they don't create a new i each time, so all the functions above would log 3 like they would if we used var). Edge 14 finally gets it right.

@MattC 2016-02-23 17:47:32

Unfortunately, 'let' is still not fully supported, especially in mobile. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

@Dan Pantry 2016-06-22 10:18:14

As of June '16, let is supported in all major browser versions except iOS Safari, Opera Mini and Safari 9. Evergreen browsers support it. Babel will transpile it correctly to keep the expected behaviour without high compliancy mode switched on.

@Ben McCormick 2016-06-27 14:24:27

@DanPantry yeah about time for an update :) Updated to better reflect the current state of things, including adding a mention of const, doc links and better compatibility info.

@pixel 67 2018-03-19 15:56:00

Isn't this why we use babel to transpile our code so browsers that don't support ES6/7 can understand what's going on?

@Bjorn Tipling 2009-04-15 06:10:50

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]();
}

Edit (2014):

Personally I think @Aust's more recent answer about using .bind is the best way to do this kind of thing now. There's also lo-dash/underscore's _.partial when you don't need or want to mess with bind's thisArg.

@aswzen 2018-04-06 01:32:18

any explanation about the }(i)); ?

@Jet Blue 2018-07-26 22:01:50

@aswzen I think it passes i as the argument index to the function.

@Abhishek Singh 2019-03-15 15:17:08

it is actually creating local variable index.

@neurosnap 2013-10-11 18:23:43

Using an Immediately-Invoked Function Expression, the simplest and most readable way to enclose an index variable:

for (var i = 0; i < 3; i++) {

    (function(index) {

        console.log('iterator: ' + index);
        //now you can also loop an ajax call here 
        //without losing track of the iterator value:   $.ajax({});
    
    })(i);

}

This sends the iterator i into the anonymous function of which we define as index. This creates a closure, where the variable i gets saved for later use in any asynchronous functionality within the IIFE.

@Kyle Falconer 2014-01-10 16:45:53

For further code readability and to avoid confusion as to which i is what, I'd rename the function parameter to index.

@Nico 2014-11-30 13:17:19

How would you use this technique to define the array funcs described in the original question?

@JLRishe 2015-03-31 20:54:35

@Nico The same way as shown in the original question, except you would use index instead of i.

@Nico 2015-04-01 09:22:44

@JLRishe var funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() {console.log('iterator: ' + index);}; })(i); }; for (var j = 0; j < 3; j++) { funcs[j](); }

@JLRishe 2015-04-01 09:40:15

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

@Nico 2015-04-01 09:45:46

@JLRishe, your version is better. I think, though, that we shouldn't recommend this answer; the use of bind is simpler and more readable.

@JLRishe 2015-04-01 09:53:31

@Nico In the general case, yes .bind() is better, but when iterating over an array, .forEach() is almost always the best option.

@JLRishe 2015-04-01 10:05:13

@Nico In OP's particular case, they're just iterating over numbers, so this wouldn't be a great case for .forEach(), but a lot of the time, when one is starting off with an array, forEach() is a good choice, like: var nums [4, 6, 7]; var funcs = {}; nums.forEach(function (num, i) { funcs[i] = function () { console.log(num); }; });

@Carsten Farving 2015-09-22 13:19:25

@Nico Actually this example solved my specific issue where I for a single value needed to make an http request and needed to keep a reference for usage in the callback and .bind nor forEach was a clean solution.

@Timar Ivo Batis 2018-12-13 15:51:13

i was looking for the syntax of immediately invoked function and couldn't figure it out. +1

@Boann 2012-08-07 08:45:35

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:

var funcs = [];
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.

@midnite 2013-12-03 02:56:23

Thanks and your solution works. But i would like to ask why this works, but swapping the var line and the return line wouldn't work? Thanks!

@Boann 2013-12-03 04:35:28

@midnite If you swapped var and return then the variable wouldn't be assigned before it returned the inner function.

@eglasius 2009-04-15 06:25:08

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]();
}

@eglasius 2009-04-15 06:54:50

@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.

@nickf 2009-04-16 00:36:09

...nor firefox. We're talking about javascript right?

@eglasius 2009-04-16 02:55:23

@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 2009-04-16 02:58:54

@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 2009-04-16 03:06:37

you can see browser support for the different versions here es.wikipedia.org/wiki/Javascript

@regisbsb 2013-10-14 17:13:31

Do not use let then

@Murtaza Hussain 2019-04-17 08:10:22

With the support of ES6, the best way to this is to use let and const keywords for this exact circumstance. So var variable get hoisted and with the end of loop the value of i gets updated for all the closures..., we can just use let to set a loop scope variable like this:

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

@B G Hari Prasad 2019-04-15 10:37:39

Use let(blocked-scope) instead of var.

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

@swogger 2019-04-07 16:45:19

  asyncIterable = [1,2,3,4,5,6,7,8];

  (async function() {
       for await (let num of asyncIterable) {
         console.log(num);
       }
    })();

@Federico Grandi 2019-04-07 18:55:51

It's always better to add some explanation to the code so that users will understand it better. Try to explain why your way is better than the ones from the other answers :)

@swogger 2019-04-08 23:01:23

Thanks @FedericoGrandi, after two pages of examples I thought that will not be required.

@Costa 2016-12-07 17:33:27

JavaScript functions "close over" the scope they have access to upon declaration, and retain access to that scope even as variables in that scope change.

var funcs = []

for (var i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

Each function in the array above closes over the global scope (global, simply because that happens to be the scope they're declared in).

Later those functions are invoked logging the most current value of i in the global scope. That's the magic, and frustration, of closure.

"JavaScript Functions close over the scope they are declared in, and retain access to that scope even as variable values inside of that scope change."

Using let instead of var solves this by creating a new scope each time the for loop runs, creating a separated scope for each function to close over. Various other techniques do the same thing with extra functions.

var funcs = []

for (let i = 0; i < 3; i += 1) {
  funcs[i] = function () {
    console.log(i)
  }
}

for (var k = 0; k < 3; k += 1) {
  funcs[k]()
}

(let makes variables block scoped. Blocks are denoted by curly braces, but in the case of the for loop the initialization variable, i in our case, is considered to be declared in the braces.)

@Modermo 2017-04-05 02:50:29

I struggled to understand this concept until I read this answer. It touches on a really important point – the value of i is being set to the global scope. When the for loop finishes running, the global value of i is now 3. Therefore, whenever that function is invoked in the array (using, say funcs[j]), the i in that function is referencing the global i variable (which is 3).

@pixel 67 2016-05-05 11:48:51

And yet another solution: instead of creating another loop, just bind the this to the return function.

var funcs = [];

function createFunc(i) {
  return function() {
    console.log('My value: ' + i); //log value of i.
  }.call(this);
}

for (var i = 1; i <= 5; i++) {  //5 functions
  funcs[i] = createFunc(i);     // call createFunc() i=5 times
}

By binding this, solves the problem as well.

@Nouman Dilshad 2018-09-05 13:00:37

Just change the var keyword to let.

var is function scoped.

let is block scoped.

When you start you code the for loop will iterate and assign the value of i to 3, which will remain 3 throughout your code. I suggest you to read more about scopes in node (let,var,const and others)

funcs = [];
for (let i = 0; i < 3; i++) {      // let's create 3 functions
  funcs[i] =async function() {          // and store them in funcs
    await 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
}

@user1559625 2018-08-01 09:32:05

This proves how ugly javascript is with regard to how 'closure' and 'non-closure' works.

In the case of:

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.
  };
}

funcs[i] is a global function, and 'console.log("My value: " + i);' is printing global variable i

In the case of

var funcs = [];

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

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

because of this twisted closure design of javascript, 'console.log("My value: " + i);' is printing the i from outer function 'createfunc(i)'

all because javascript can not design something decent like the 'static' variable inside a function like what C programming language is doing!

@ashish yadav 2018-07-13 08:02:09

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

@stemon 2018-05-25 00:18:33

Why not simply call each function inside the first (and only) loop just after they were created, such as:

 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.
    };
    funcs[i]();// and now let's run each one to see
    }

@nickf 2018-05-31 09:22:48

Because it was just an example of the problem.

@Mark Manning 2018-03-28 20:15:11

Ok. I read through all of the answers. Even though there is a good explanation here - I just could not get this to work. So I went looking on the internet. The person at https://dzone.com/articles/why-does-javascript-loop-only-use-last-value had an answer which is not presented here. So I thought I'd post a short example. This made a lot more sense to me.

The long and short of it is that the LET command is nice but is only now being used. HOWEVER, the LET command is really just a TRY-CATCH combo. This works all the way back to IE3 (I believe). Using the TRY-CATCH combo - life is simple and good. Probably why the EMCScript people decided to use it. It also does not need a setTimeout() function. So no time is lost. Basically, you need one TRY-CATCH combo per FOR loop. Here is an example:

    for( var i in myArray ){
       try{ throw i }
       catch(ii){
// Do whatever it is you want to do with ii
          }
       }

If you have more than one FOR loop, you just put a TRY-CATCH combo for each one. Also, personally, I always use the double letter of whatever FOR variable I am using. So "ii" for "i" and so on. I am using this technique in a routine to send mouseover commands to a different routine.

@Eyal Segal 2018-03-14 06:19:14

Let's say you don't use es6; You can use IFFY function:

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

But it will be different.

@woojoo666 2015-04-10 09:57:07

Bit late to the party, but I was exploring this issue today and noticed that many of the answers don't completely address how Javascript treats scopes, which is essentially what this boils down to.

So as many others mentioned, the problem is that the inner function is referencing the same i variable. So why don't we just create a new local variable each iteration, and have the inner function reference that instead?

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    var ilocal = i; //create a new local variable
    funcs[i] = function() {
        console.log("My value: " + ilocal); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

Just like before, where each inner function outputted the last value assigned to i, now each inner function just outputs the last value assigned to ilocal. But shouldn't each iteration have it's own ilocal?

Turns out, that's the issue. Each iteration is sharing the same scope, so every iteration after the first is just overwriting ilocal. From MDN:

Important: JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.

Reiterated for emphasis:

JavaScript does not have block scope. Variables introduced with a block are scoped to the containing function or script

We can see this by checking ilocal before we declare it in each iteration:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
  console.log(ilocal);
  var ilocal = i;
}

This is exactly why this bug is so tricky. Even though you are redeclaring a variable, Javascript won't throw an error, and JSLint won't even throw a warning. This is also why the best way to solve this is to take advantage of closures, which is essentially the idea that in Javascript, inner functions have access to outer variables because inner scopes "enclose" outer scopes.

Closures

This also means that inner functions "hold onto" outer variables and keep them alive, even if the outer function returns. To utilize this, we create and call a wrapper function purely to make a new scope, declare ilocal in the new scope, and return an inner function that uses ilocal (more explanation below):

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = (function() { //create a new scope using a wrapper function
        var ilocal = i; //capture i into a local var
        return function() { //return the inner function
            console.log("My value: " + ilocal);
        };
    })(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}

Creating the inner function inside a wrapper function gives the inner function a private environment that only it can access, a "closure". Thus, every time we call the wrapper function we create a new inner function with it's own separate environment, ensuring that the ilocal variables don't collide and overwrite each other. A few minor optimizations gives the final answer that many other SO users gave:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (var i = 0; i < 3; i++) {
    funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
    funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
    return function() { //return the inner function
        console.log("My value: " + ilocal);
    };
}

Update

With ES6 now mainstream, we can now use the new let keyword to create block-scoped variables:

//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};

var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
    funcs[i] = function() {
        console.log("My value: " + i); //each should reference its own local variable
    };
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
    funcs[j]();
}

Look how easy it is now! For more information see this answer, which my info is based off of.

@CapturedTree 2017-10-26 21:45:21

I like how you explained the IIFE way as well. I was looking for that. Thank you.

@user4639281 2017-12-27 03:12:06

There is now such a thing as block scoping in JavaScript using the let and const keywords. If this answer were to expand to include that, it would be much more globally useful in my opinion.

@woojoo666 2018-03-01 22:44:09

@TinyGiant sure thing, I added some info about let and linked a more complete explanation

@nutty about natty 2018-05-14 19:08:24

@woojoo666 Could your answer also work for calling two alternating URL's in a loop like so: i=0; while(i < 100) { setTimeout(function(){ window.open("https://www.bbc.com","_self") }, 3000); setTimeout(function(){ window.open("https://www.cnn.com","_self") }, 3000); i++ }? (could replace window.open() with getelementbyid......)

@woojoo666 2018-06-03 22:58:23

@nuttyaboutnatty sorry about such a late reply. It doesn't seem like the code in your example already works. You aren't using i in your timeout functions, so you don't need a closure

@woojoo666 2018-06-08 11:22:45

whoops, sorry, meant to say "it seems like the code in your example already works"

@Brooks DuBois 2018-02-25 03:15:21

While this question is old and answered, I have yet another fairly interesting solution:

var funcs = [];

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

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

The change is so small it's almost difficult to see what I did. I switched the second iterator from a j to an i. This somehow refreshes the state of i in time to give you the desired result. I did this by accident but it makes sense considering previous answers.

I wrote this up to point out this small, yet very important difference. Hope that helps to clear up some confusion for other learners like me.

Note: I am not sharing this because I think it's the right answer. This is a flakey solution that probably will break under certain circumstances. Actually, I'm quite amazed that it really works.

@nickf 2018-03-15 21:04:45

It's only working because in the second loop, you're overwriting the same i as is referenced in the function. Just consider that in this whole snippet, there is only one i variable. It is equivalent to: i = 0; funcs[0](); i = 1; funcs[1](); ..

@Brooks DuBois 2018-03-16 00:51:31

right, which makes sense considering the other answers about scoping, but still is sort of counterintuitive

@Aust 2013-10-11 16:41:56

Another way that hasn't been mentioned yet is the use of Function.prototype.bind

var funcs = {};
for (var i = 0; i < 3; i++) {
  funcs[i] = function(x) {
    console.log('My value: ' + x);
  }.bind(this, i);
}
for (var j = 0; j < 3; j++) {
  funcs[j]();
}

UPDATE

As pointed out by @squint and @mekdev, you get better performance by creating the function outside the loop first and then binding the results within the loop.

function log(x) {
  console.log('My value: ' + x);
}

var funcs = [];

for (var i = 0; i < 3; i++) {
  funcs[i] = log.bind(this, i);
}

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

@Bjorn Tipling 2014-12-08 05:18:31

This is what I do these days too, I also like lo-dash/underscore's _.partial

@user1106925 2015-06-28 03:29:07

.bind() will be largely obsolete with ECMAScript 6 features. Besides, this actually creates two functions per iteration. First the anonymous, then the one generated by .bind(). Better use would be to create it outside the loop, then .bind() it inside.

@mekdev 2015-06-28 18:32:17

Doesn't this trigger JsHint - Don't make functions within a loop. ? I went down this path also but after running code quality tools its a no go..

@Aust 2015-06-29 16:23:27

@squint @mekdev - You both are correct. My initial example was written quickly to demonstrate how bind is used. I've added another example per your suggestions.

@user2290820 2015-09-11 12:14:20

I think instead of wasting computation over two O(n) loops, just do for (var i = 0; i < 3; i++) { log.call(this, i); }

@niry 2017-01-08 05:55:07

.bind() does what the accepted answer suggests PLUS fiddles with this.

@Todd Chaffee 2019-06-10 20:48:22

This is an abuse of bind for the purpose of creating a closure and is not what bind was intended for. Just create your own closure. Or by now, use let in your for loop.

@Bimal Das 2018-01-16 14:29:57

We will check , what actually happens when you declare var and let one by one.

Case1 : using var

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

Now open your chrome console window by pressing F12 and refresh the page. Expend every 3 functions inside the array.You will see an property called [[Scopes]].Expand that one. You will see one array object called "Global",expand that one. You will find a property 'i' declared into the object which having value 3.

enter image description here

enter image description here

Conclusion:

  1. When you declare a variable using 'var' outside a function ,it becomes global variable(you can check by typing i or window.i in console window.It will return 3).
  2. The annominous function you declared will not call and check the value inside the function unless you invoke the functions.
  3. When you invoke the function , console.log("My value: " + i) takes the value from its Global object and display the result.

CASE2 : using let

Now replace the 'var' with 'let'

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

Do the same thing, Go to the scopes . Now you will see two objects "Block" and "Global". Now expand Block object , you will see 'i' is defined there , and the strange thing is that , for every functions , the value if i is different (0 , 1, 2).

enter image description here

Conclusion:

When you declare variable using 'let' even outside the function but inside the loop , this variable will not be a Global variable , it will become a Block level variable which is only available for the same function only.That is the reason , we are getting value of i different for each function when we invoke the functions.

For more detail about how closer works , please go through the awesome video tutorial https://youtu.be/71AtaJpJHw0

@sidhuko 2018-01-13 13:17:57

This question really shows the history of JavaScript! Now we can avoid block scoping with arrow functions and handle loops directly from DOM nodes using Object methods.

const funcs = [1, 2, 3].map(i => () => console.log(i));
funcs.map(fn => fn())

const buttons = document.getElementsByTagName("button");
Object
  .keys(buttons)
  .map(i => buttons[i].addEventListener('click', () => console.log(i)));
<button>0</button><br>
<button>1</button><br>
<button>2</button>

@Kemal Dağ 2013-06-25 14:21:53

The most simple solution would be,

Instead of using:

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

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

which alerts "2", for 3 times. This is because anonymous functions created in for loop, shares same closure, and in that closure, the value of i is the same. Use this to prevent shared closure:

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

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

The idea behind this is, encapsulating the entire body of the for loop with an IIFE (Immediately-Invoked Function Expression) and passing new_i as a parameter and capturing it as i. Since the anonymous function is executed immediately, the i value is different for each function defined inside the anonymous function.

This solution seems to fit any such problem since it will require minimal changes to the original code suffering from this issue. In fact, this is by design, it should not be an issue at all!

@DanMan 2013-07-26 11:18:39

Read something similar in a book once. I prefer this, too, since you don't have to touch your existing code (as much) and it becomes obvious why you did it, once you've learned the self-calling function pattern: to trap that variable in the newly created scope.

@Kemal Dağ 2013-07-26 12:20:44

@DanMan Thanks. Self calling anonymous functions are very good way to deal javascript's lack of block level variable scope.

@jherax 2015-10-27 04:29:35

Self-calling, or self-invoking is not the appropriate term for this technique, IIFE (Immediately-Invoked Function Expression) is more accurately. Ref: benalman.com/news/2010/11/…

@axelduch 2015-05-06 22:33:08

This is a problem often encountered with asynchronous code, the variable i is mutable and at the time at which the function call is made the code using i will be executed and i will have mutated to its last value, thus meaning all functions created within the loop will create a closure and i will be equal to 3 (the upper bound + 1 of the for loop.

A workaround to this, is to create a function that will hold the value of i for each iteration and force a copy i (as it is a primitive, think of it as a snapshot if it helps you).

@Vikash Singh 2017-01-20 10:02:32

Use closure structure, this would reduce your extra for loop. You can do it in a single for loop:

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

@jsbisht 2017-07-17 10:10:55

COUNTER BEING A PRIMITIVE

Let's define callback functions as follows:

// ****************************
// COUNTER BEING A PRIMITIVE
// ****************************
function test1() {
    for (var i=0; i<2; i++) {
        setTimeout(function() {
            console.log(i);
        });
    }
}
test1();
// 2
// 2

After timeout completes it will print 2 for both. This is because the callback function accesses the value based on the lexical scope, where it was function was defined.

To pass and preserve the value while callback was defined, we can create a closure, to preserve the value before the callback is invoked. This can be done as follows:

function test2() {
    function sendRequest(i) {
        setTimeout(function() {
            console.log(i);
        });
    }

    for (var i = 0; i < 2; i++) {
        sendRequest(i);
    }
}
test2();
// 1
// 2

Now what's special about this is "The primitives are passed by value and copied. Thus when the closure is defined, they keep the value from the previous loop."

COUNTER BEING AN OBJECT

Since closures have access to parent function variables via reference, this approach would differ from that for primitives.

// ****************************
// COUNTER BEING AN OBJECT
// ****************************
function test3() {
    var index = { i: 0 };
    for (index.i=0; index.i<2; index.i++) {
        setTimeout(function() {
            console.log('test3: ' + index.i);
        });
    }
}
test3();
// 2
// 2

So, even if a closure is created for the variable being passed as an object, the value of the loop index will not be preserved. This is to show that the values of an object are not copied whereas they are accessed via reference.

function test4() {
    var index = { i: 0 };
    function sendRequest(index, i) {
        setTimeout(function() {
            console.log('index: ' + index);
            console.log('i: ' + i);
            console.log(index[i]);
        });
    }

    for (index.i=0; index.i<2; index.i++) {
        sendRequest(index, index.i);
    }
}
test4();
// index: { i: 2}
// 0
// undefined

// index: { i: 2}
// 1
// undefined

@Buksy 2016-11-04 08:58:29

Your code doesn't work, because what it does is:

Create variable `funcs` and assign it an empty array;  
Loop from 0 up until it is less than 3 and assign it to variable `i`;
    Push to variable `funcs` next function:  
        // Only push (save), but don't execute
        **Write to console current value of variable `i`;**

// First loop has ended, i = 3;

Loop from 0 up until it is less than 3 and assign it to variable `j`;
    Call `j`-th function from variable `funcs`:  
        **Write to console current value of variable `i`;**  
        // Ask yourself NOW! What is the value of i?

Now the question is, what is the value of variable i when the function is called? Because the first loop is created with the condition of i < 3, it stops immediately when the condition is false, so it is i = 3.

You need to understand that, in time when your functions are created, none of their code is executed, it is only saved for later. And so when they are called later, the interpreter executes them and asks: "What is the current value of i?"

So, your goal is to first save the value of i to function and only after that save the function to funcs. This could be done for example this way:

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

This way, each function will have it's own variable x and we set this x to the value of i in each iteration.

This is only one of the multiple ways to solve this problem.

@Ali Kahoot 2016-11-04 07:46:07

First of all, understand what's wrong with this code:

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
}

Here when the funcs[] array is being initialized, i is being incremented, the funcs array is initialized and the size of func array becomes 3, so i = 3,. Now when the funcs[j]() is called, it is again using the variable i, which has already been incremented to 3.

Now to solve this, we have many options. Below are two of them:

  1. We can initialize i with let or initialize a new variable index with let and make it equal to i. So when the call is being made, index will be used and its scope will end after initialization. And for calling, index will be initialized again:

    var funcs = [];
    for (var i = 0; i < 3; i++) {          
        let index = i;
        funcs[i] = function() {            
            console.log("My value: " + index); 
        };
    }
    for (var j = 0; j < 3; j++) {
        funcs[j]();                        
    }
    
  2. Other Option can be to introduce a tempFunc which returns the actual function:

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

Related Questions

Sponsored Content

39 Answered Questions

[SOLVED] Loop through an array in JavaScript

54 Answered Questions

[SOLVED] Loop inside React JSX

  • 2014-04-05 05:29:28
  • Ben Roberts
  • 699570 View
  • 1056 Score
  • 54 Answer
  • Tags:   javascript reactjs

37 Answered Questions

[SOLVED] How do I loop through or enumerate a JavaScript object?

12 Answered Questions

[SOLVED] Google Maps JS API v3 - Simple Multiple Marker Example

20 Answered Questions

[SOLVED] What is a practical use for a closure in JavaScript?

21 Answered Questions

[SOLVED] How to loop through a plain JavaScript object with the objects as members?

  • 2009-05-28 16:18:14
  • edt
  • 1520787 View
  • 1462 Score
  • 21 Answer
  • Tags:   javascript

34 Answered Questions

[SOLVED] Function overloading in Javascript - Best practices

86 Answered Questions

[SOLVED] How do JavaScript closures work?

12 Answered Questions

[SOLVED] JavaScript closures vs. anonymous functions

0 Answered Questions

Combining functions inside object: closures and 'this'

Sponsored Content