2

I've been studying closures lately and beginning to get a hang of it, i understood from contents online and from my former question here that closures are created when a function is created inside another function (Don't know if this is the only condition for closure to exist). I decided to experiment more on this and these set of code got me confused, i didn't expect the output.

var f = [];
for(var i = 0; i < 3; i++){
  f[i] = function(){
    console.log("Number " + i);
   }
};

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

//Actual Output
//Number 0
//Number 1
//Number 2

//Expected output
//Number 3
//Number 3
//Number 3

I think i should also mention that when i replaced the second loop with Function.forEach like this

f.forEach(function(i){
  i();
});

it printed the expected output. What am i missing?

Community
  • 1
  • 1

1 Answers1

5

The problem is that you are redefining the i variable. With variable hoisting, your code is interpreted as:

var f = [];
var i;

for(i = 0; i < 3; i++){
  f[i] = function(){
    console.log("Number " + i);
   }
};

for(i = 0; i < 3; i++){
    // `i` is set back to 0 -> 3
    f[i]();
}

When you switch it with the forEach loop, you don't change the i variable and your closed over function works as expected.

If you want to continue to use a native for, just change var i to var j.

TbWill4321
  • 8,626
  • 3
  • 27
  • 25
  • I was thinking the scope of i in the first loop should end with the closing brace of the loop, i guess JavaScript is a lot different from Java after all –  Dec 03 '15 at 22:52
  • JavaScript didn't get block scoping until recently with the `let` and `const` keywords. You can use `let` in your `for` loops for the expected result once it's implemented everywhere, or if you transpile your code. – TbWill4321 Dec 03 '15 at 22:56