For loop , scoping and function calling

let printNumTwo;
for (let i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());

above
gives output 2

var printNumTwo;
for (var i = 0; i < 3; i++) {
if (i === 2) {
printNumTwo = function() {
return i;
};
}
}
console.log(printNumTwo());

this gives output 3

     one can see in both cases 'i' is being incremented to 3 and I know scoping of let is as wide as the block it is defined in so function should be able to get 'i=3' in both programs its like in program one it is showing results as if it was executed before hand and then at console log its showing the pre executed state . but in prog 2 it is working as if we can call that function and get i's status

Hi @RishiDt ,

It took me a while to understand your question as your code is not very readable.

I can’t really help but I would Also like to know the answer! I’ve reposted the code below.

What about the scoping of printNumTwo causes these two code blocks to return different answers?
Block 1:

let printNumTwo;
for (let i = 0; i < 3; i++){
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo()); // 2

Block 2:

var printNumTwo;
for (var i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo()); // 3
1 Like

So after a bit of playing it turns out that it has nothing to do with the scoping of printNumTwo. It is actually the scoping of i.
In either code block for (let i ... returns 2 and for (var i.. returns 3.

As you don’t call printNumTwo until after the for loop I’m guessing the global var scoping of i allows the function to grab the final value where as the block scoping of let only lets you get that single value. Still probably best to get someone more experienced like @JeremyLT to have a look and explain it.

Yes. But what I am unable to figure is in both cases printNumTwo has i available to it. and it is going to be 3 in both cases although block wont be executed in both for loops. but only the 2nd program function is able to return 3.

@damianicely dont you agree that i is going to be 3 in both cases

Well you instantiate printNumTwo outside of the for loop in both cases. Although you change it inside the loop that definition will then hold anywhere outside as that was where it was defined in the first place.

So it is very obvious what is happening in this case:

  1. var printNumTwo; AND var i
console.log(i); // 3
console.log(printNumTwo()); //3

what happened: You define a global variable printNumTwo THEN you start a for loop where you define another global variable i. Inside the loop you change the definition of printNumTwo to return i. The loop completes with i at three. you call printNumTwo and it does as its told and returns three.

But in this case
2. (var printNumTwo; OR var printNumTwo; )AND let i

i is scoped to the for loop so kind of only exists inside that loop.
if you console log i outside you’ll get
ReferenceError: i is not defined
How it is that you can run printNumTwo and get i anything at all is the interesting question. The javascript must have noted what i was at the moment you changed the definition of printNumTwo

let printNumTwo;
for (var i = 0; i < 3; i++){
printNumTwo = function() {
return i;
}
}
console.log(printNumTwo());

this gives 3

let printNumTwo;
for (let i = 0; i < 3; i++){
printNumTwo = function() {
return i;
}
}
console.log(printNumTwo());

that gives 2

exactly. It is the scoping of i that matters. In fact if you modify the second block. to set i to 6 after the for loop it will STILL return 2

let printNumTwo;
for (let i = 0; i < 3; i++){
printNumTwo = function() {
return i;
}
}
var i = 6;
console.log(printNumTwo());

But if you do the same with the first block you will get 6

let printNumTwo;
for (var i = 0; i < 3; i++){
printNumTwo = function() {
return i;
}
}
var i = 6;
console.log(printNumTwo());

thats because local and global scoping

@RishiDt the for-loop with the let creates a brand new i variable each time though the loop, so the “2” is captured in the function, but the var version of the for-loop reuses the same variable in each iteration, so you see the final value when you call the function.

Interesting question! Let me know if that explanation makes sense, I can make it more technically accurate, but hopefully you get the idea.

This is a great demonstration of the purpose of the let keyword.

Correct. In a for-loop you have a new block in each iteration. You write the block one time, but it each time it runs it’s a new block, just like of it call a function where you’ve declared variables with let the variables fall out of scope between function calls.

let printNumTwo;
for (var i = 0; i < 3; i++){
  console.log(i); //0  1  2
}
let printNumTwo;
for (let i = 0; i < 3; i++){
  console.log(i);// 0 1  2
}

the function inside loop is called out of the loop to fetch the i okay. now as you can see in the code above that i inside loop can only be upto 2. i think the function where var is used is sending the global i. whereas the function where let is used is sending local i (inside the loop). inside the loop i can only be which is allowed by the condition. but when using var the i allowed to function is global that means the one that was altered in increment (global scoped).

for the program with let this implies that i in the for statement and in the block has to be different.

let printNumTwo;
for (let i = 0; i < 3; i++){
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(i);//undefined
console.log(printNumTwo()); // 2

var printNumTwo;
for (var i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(i);//3

console.log(printNumTwo()); // 3