0

Functions has access to it own lexical as well outer environment but it's not working or maybe I don't understand why it's working like that.

Here is the code

function makeArmy() {
    let shooters = [];
  
    let i = 0;
    while (i < 10) {
      let shooter = function() {
        console.log( i );
      };
      shooters.push(shooter);
      i++;
    }

    return shooters;
  }
  
  let army = makeArmy();
  
  // all shooters show 10 instead of their numbers 0, 1, 2, 3...
  army[0](); // 10 from the shooter number 0
  army[1](); // 10 from the shooter number 1
  army[2](); // 10 ...and so on.

Fixed code


while (i < 10) {
      let j = i; // added variable to while loop (lexical  environment)
      let shooter = function() { 
        alert( j );
      };
    shooters.push(shooter);
    i++;
  }

But why don't it work like this when i define variable with J inside the function! Shooter function has it's own lexical environment.


while (i < 10) {
      let shooter = function() {
      let j = i; // define J inside function but still it gives 10 why?
        console.log( j );
      };
      shooters.push(shooter);
      i++;
    }

Akhil Rana
  • 145
  • 2
  • 12
  • 1
    Your variable `i` is declared **outside** the `while` loop. Thus all the constructed functions in the loop share the same `i`, and at the end of the loop its value is 10. – Pointy Mar 13 '23 at 17:48
  • But we define j variable within the function and now it has variable store inside it lexical scope. Why it's not reference that j? What di mean by the constructed function? – Akhil Rana Mar 13 '23 at 17:58
  • 2
    The function you make with the function expression in the loop. It relies on a reference to `i`, and `i` is that variable declared with `let` before the loop. – Pointy Mar 13 '23 at 18:00

2 Answers2

2

Even though you define the variable j inside of the function (let j), you aren't initializing that variable (j = i) until the function gets executed.

At the time when the function instance is created, the reference to the outer variable i is "closed over," so the function can access the value of i when it gets executed. But it's not executed until after you've completed the loop, so let j = i causes j to have the same value that i has at the end of your loop.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
0

Kind of the same code but simpler

let x = 0
const a = []
a.push(() => console.log(x))
{
  // creates a new variable
  const y = x
  a.push(() => console.log(y))
}
// x is changed but y is not
x = 1
// prints 1
a[0]()
// prints 0
a[1]()
Konrad
  • 21,590
  • 4
  • 28
  • 64
  • 2
    This shows why the "fix" works, but it doesn't explain why the final code snippet doesn't work, with a variable declared _inside_ of one of the lambda expressions. – StriplingWarrior Mar 13 '23 at 18:08