-1

I do understand the javascript closure as I think and I did a lot of small programs with it but in this code what I didn't understand is When I call the functions in the array why they are printing out different values of "i" aren't they suppose to refer to the same "i"?

function makeFunctionArray() {
      const arr = []
    
      //let i = 0
      for (let i = 0; i < 5; i++) {
        arr.push(function () { console.log(i) })
      }
      
      //console.log(i)
    
      return arr
    }
    
    let functionarr = makeFunctionArray() 
    functionarr[0]() //print out 0
    functionarr[2]() //print out 2
    functionarr[1]() //print out 1
Zahal A_Omer
  • 111
  • 1
  • 7
  • 1
    `let` creates block scoped variable - try with `var i` and see the difference – Bravo Jul 12 '21 at 23:15
  • @Bravo I know that I know that "var" is a function scooped but why arr-functions print out d/f "i"? – Zahal A_Omer Jul 12 '21 at 23:20
  • What you are describing is the very definition of a closure, each function maintains a reference to its specific lexical environment, and thus to the value of any locally scoped variables within that environment. see: [Closure](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures#closure) – pilchard Jul 13 '21 at 00:06
  • @pilchard i get it but you know that var and let is what is making the d/f so i need why but now i think i know that when var is function scooped and let is block scooped and that when let is used it uses what just that block value is but the var is function scooped so it refer to the fuction value am i right? – Zahal A_Omer Jul 13 '21 at 03:00

1 Answers1

-2
  • When you do

      for (let i = 0; i < 5; i++) {
          arr.push(function () { console.log(i) })
      }
    

The arr would have the values

[console.log(0),
 console.log(1),
 console.log(2),
 console.log(3),
 console.log(4)];

So when you return arr and then you call functionarr like this

functionarr[0]() //print out 0
functionarr[2]() //print out 2
functionarr[1]() //print out 1

It would return:

console.log(0);
console.log(1);
console.log(2);

REMEMBER : it is an scope issue. If you use var, when you call the i variable into the array function, it would return the last i value. Thats the reason of why it returns always 5. If you use let, it would return the local i value, so it would save [0, 1, 2, 3, 4].

  • Using let

const arr = [];

for (let i = 0; i < 5; i++) {
    arr.push(
      function () { 
        console.log(i);   //i value at the moment that you create function would be saved 
      }
    );  
}

arr[0]();  //print 0
  • Using var

const arr = [];

for (var i = 0; i < 5; i++) {
    arr.push(
      function () { 
        console.log(i);   //final i value would be saved (current i value)
      }
    );  
}

arr[0]();  //print 5
AlexSp3
  • 2,201
  • 2
  • 7
  • 24
  • ok thanks, but when I use var it will print 5 so why it will print 5 if the value of the "i" is already saved in the array? – Zahal A_Omer Jul 12 '21 at 23:42
  • Well, It is an scope issue. If you use `var`, when you call the `i` variable into the array function, it would return the last `i` value. Thats the reason of why it returns always `5`. If you use `let`, it would return the local `i` value, so it would save `[0, 1, 2, 3, 4]`. – AlexSp3 Jul 12 '21 at 23:47
  • Look at my updated answer for an example, run the snippets – AlexSp3 Jul 12 '21 at 23:59
  • 1
    Your description isn't actually accurate. The array contains `[function(){console.log(i)},function(){console.log(i)}...]` but each `i` references a different variable. You could declare a second function within the same lexical scope that altered `i` and the existing functions would reflect that (and maintain separation between themselves). – pilchard Jul 13 '21 at 00:21
  • @ZahalA_Omer Glad it helped you :) – AlexSp3 Jul 13 '21 at 15:48