Compare Scopes of the var and let Keywords

Tell us what’s happening:

HELP. I don’t quite get why this example would return 3.

Shouldn’t the loop stop when variable i reaches 2, which means that it would stop “incrementing”? So how did it reach the value of 3?


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

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/compare-scopes-of-the-var-and-let-keywords

1 Like

read this

Hi, thank you.

Please elaborate?

I already understand the === comparator.

In the example, i is an integer, and it is comparing it to 2 in the if-statement.
So when (i === 2), it should execute the function printNumTwo right? And i IS 2 during that time, so how did it return 3 in the end?

“As you can see, printNumTwo() prints 3 and not 2. This is because the value assigned to i was updated and the printNumTwo() returns the global i and not the value i had when the function was created in the for loop. The let keyword does not follow this behavior:”

Hi @sjkayle,

The problem is because you use var keyword rather than let keyword.
by using var keyword: you update variable globally so it give you 3
if you use let keyword: you fix this problem and make the variable locally updated.

This is the solution of example

function checkScope() {
"use strict";
  let i = "function scope";
  if (true) {
    let i = "block scope";
    console.log("Block scope i is: ", i);
  }
  console.log("Function scope i is: ", i);
  return i;
}

Hope this solve your problem, good luck my friend :slight_smile:

Regards,
Ali Mosaad

Hi @sjkayle

I think people are missing the actual point of your question so i’ll post a copy of my response to the same question on an identical thread:

So I’ve been racking my brain over this one for a few minutes. I sat here thinking exactly the same thing and couldn’t for the life of me understand why 3 was being returned instead of 2… and then EUREKA! And boy do I feel stupid now…

Actually, I say that, but quite frankly the formatting of the example code could be improved here.

So here we go:

We have a for loop. As i’m sure you’ve picked up by now for loops work in this pattern…
set variable (var i = 0; in this case) --> execute following code (numArray.push(i)) where condition is true (i<3) --> do something at the end of each iteration (increment i with i++).

We can follow through each iteration of the loop to see what happens!
Iteration 1:

i starts as 0
i is less than 3 so i (0 at the moment) is pushed to the array
i is incremented by 1 to become 1

Iteration 2:

i starts as 1
i is less than 3 so i (1 at the moment) is pushed to the array
i is incremented by 1 to become 2

Iteration 3:

i starts as 2
i is less than 3 so i (2 at the moment) is pushed to the array
i is incremented by 1 to become 3

Iteration 4:

i starts as 3
i is NOT LESS THAN 3 so loop ceases execution

So at this point our loop has ended. Notice how when i is incremented in the third iteration that it takes the value 3, this is what causes the loop to exit (before executing code) on the next iteration.
This is why now, when we get the console to log i, it returns 3.

I find it really helps to work through iterations of loops in situations like this!

Now then, if you’re thinking to yourself “but if the printNumTwo function only gets called when i === 2, how can we call it when i is not 2?”, then you wouldn’t be alone because I did exactly this as well.

Whats important here is that the printNumTwo function is called WITHIN THE LOOP WHEN i === 2. We can still call on this specific function anywhere else as we normally would. Heck, all this function does is return i so the final line console.log(printNumTwo()) is essentially identical to console.log(i). As we can see from the end of our third iteration of the loop i === 3

Hope this helps!

10 Likes

Thank you! I now understand it.

I honestly still don’t get it. Can you please explain this for me? How does this return a 3…

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

and… why does the following returns a 2…?

'use strict';
let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo());
// returns 2
console.log(i);
// returns "i is not defined"

Inside this loop, when i is 2, the function is created. The function returns i. A variable declared with var is global, at the end of the loop i is 3, and as the variable is global, the function returns whatever number the variable is.

When a function is declared with let instead it is block scoped, as in is defined only inside the block (a block is surrounded by graph parenthesis {}

So the function can read only the value the variable was where/when the function was declared here:

You can try to visualise the difference using this tool, it is subtle but may be seen
http://pythontutor.com/javascript.html

1 Like

still pretty confusing :confused:

i don’t get why when i===2 it doesn’t execute the function but instead goes back up to the if statement to increment 2 to 3 then return it

This is a function declaration, it doesn’t execute the function

Instead you call the function with printNumTwo(), and it is with this call that the function execute

2 Likes

exactly its suppose to call the function and then executes whats inside it. and what is inside the function is basically “return i”. but i looked at the visualiser, it shows it go back up to increment 1 again then returning it… i can’t understand that.

"As you can see, printNumTwo() prints 3 and not 2. This is because the value assigned to i was updated and the printNumTwo() returns the global i and not the value i"

okay so the global i is “var i” in the for condition… where is the other “value i”?

The value i had when the function was declared

still dont get it unfortunately…

i read ur previous comments again and i think i understand it… but not completely in reason… i spent like 2h+ on this… and its driving me crazy. i think im gonna go the next challenge.

TLDR: Use let and const, not var yo declare your variables, as they are new

yeah i did. finishing the challenge is no problem and i understand it but the examples shown on the left is what questions me.

The difference is that

for (let i = 0; i < 4; i++) {}
console.log(i) // undefined because the value of a function declared with let is block scoped 

for (var j = 0; j < 4; j++) {}
console.log(j); // j is 4

Finally got it after some readings here, hopefully I can help some more. The confusion is probably by one of these two:

  1. why is the “var” example giving 3 instead of 2, when the return statement is in the i ===2 conditional?
  • the function printNumTwo was created/assigned in the for loop, not called! so the “return i;” is executed after the for loop is over, at which time the value of i was already incremented to 3.
  1. why is the “let” example giving 2 instead of 3, if value of i was incremented to 3 already in the for loop?
  • the let keyword is block scoped, i.e. between { }, not function scoped or globally scoped, so the i value returned is specific within the block:
 if (i === 2) {
    printNumTwo = function() {
      return i;
    };

at which time, the value of i is 2 (since it is the condition to enter that block).

3 Likes

mhmm :thinking: so no matter how many times we iterate. it doesn’t even matter if we use the “let” keyword. its blockscoped meaning it returns within the if statement regardless? i tested with the code myself:

'use strict';
let printNumTwo;
for (let i = 0; i < 612312320; i++) {
  if (i === 7) {
    printNumTwo = function() {
      return i;
    };
  }


}
console.log(printNumTwo());
// returns 7
console.log(i);
// returns "i is not defined"

wow… thank you man i finally understood this concept! you made it really simple to understand! :grin: after like freakin 20 days.

1 Like