closure inside a loop

2

I have the following code, I do not understand the result

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

Should it be the output 0 1 2? but instead it's: 3 3 3.

Any explanation?

    
asked by hubman 30.12.2016 в 06:19
source

2 answers

3

The solution would be to use let in for (let i = 0; i < 3; i++) , as shown in this code:

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

If I'm not mistaken, this is due to the scope of var and let . The scope of var is the function it is in (and if it is not within a function, as was your case, it is a global variable), while the scope of let is the block in which it is define (after the change, only the loop for ).

With var , when you call the functions of funcs[] , there is a global variable i that has the value 3, so that is the value that is returned in the console. Whereas if you use let , then there is no global variable i only the "local" value of i when the function was created and what you expect is returned.

    
answered by 30.12.2016 / 06:33
source
5

As Alvaro indicates, the problem is due to the scope, let defines variables available within the code block immediately above, while var defines a variable in the scope of the immediately superior function, with let you are defining the variable within the code block of the for while with var you define it within the scope of the function where the code is or global if it is not inside a function, the solution of Alvaro works with ES6 but if you want to do it in previous versions you must create a new scope for each iteration and the only way to do it is by creating a function that creates a new scope in the iteration of the for, in this way.

var funcs = [];
for (var i = 0; i < 3; i++) {   
  funcs.push((function(valor) {     
    return function() {
       console.log("el valor es: " + valor); 
    }
  })(i));
}
for (var j = 0; j < 3; j++) {
  funcs[j]();                     
}

This is compatible in ES5

    
answered by 30.12.2016 в 06:56