Prakash Tiwari
Prakash Tiwari

Reputation: 2429

Using the same variable in the loops for solving the, "Closures in the loop" issue

In continuation to this question, I tried the following code that uses the same variable in both the loops and I get the desired result. My question is, WHY ?

So the initial code is:

 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]();                      // this will not give desired output
 }

The outputs this:

Whereas, the intended output is:

Now, if I use variable 'i' (a global variable) in the second loop as well, the code looks like:

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 ( i = 0; i < 3; i++) {
  funcs[i]();                      // this gives desired output
}

I get the intended output,

WHY?

Upvotes: 3

Views: 61

Answers (2)

rabbitco
rabbitco

Reputation: 2850

Now, if I use variable 'i' (a global variable) in the second loop as well ... I get the intended output ... WHY?

Because when you do the first executing loop:

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

the loop constructing the array has finished and the global variable i has the value 3 and therefore console.log(i) results in logging 3 to the console for each iteration of the first executing loop. When you do the second executing loop:

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

you for each iteration of the loop assign a new value to the global variable i and it is this new value that the console.log(i) will log to the console: 0, 1, 2.

How do you achieve the desired result in a simple way?

You can use let to achieve the desired result in a simple way:

"use strict"; // use of let requires strict mode

var funcs = [];

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

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

Now the array will be constructed with functions having access to a local variable, which is assigned the value of i at the time of adding the function to the array.

Upvotes: 2

shuangwhywhy
shuangwhywhy

Reputation: 5625

Because the variable i is contaminated. In your snippets, The loops write to the same variable i and the functions reads it. Note that there is just one variable i in your code.

What you really need to get your intended result is called "module pattern", which wraps a function to keep a local copy of the variable in the loop:

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

You can read this article to get more information about "module pattern".

Upvotes: 1

Related Questions