[Confused] ES6: Compare Scopes of the var and let Keywords

Hi everyone, I’m on the first exercise of the ES6 part of the JavaScript course.

I’m a little stuck, and would be most grateful for any help from the community, thanks in advance.

Here’s the link to the exercise: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/es6/compare-scopes-of-the-var-and-let-keywords

The exercise provides 4 examples at the start (before the main challenge), and I have trouble understanding examples #3 and #4. I can kind of guess what’s happening but really not sure.

Example 3 (provided before the challenge):

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

I’ve attached an image with numbers indicating the order in which I think the code is being executed.

My understanding is that we first call “printNumTwo()”. This then takes us to the “for” loop. We then initialize the counter with “var i = 0” then we look at the condition “i < 3” that needs to be true for the body of the “for” loop to execute.

Both “i === 0” and “i === 1” are less than 3, so we move on in the code, but since in both cases “i” is not === 2, nothing happens.

We finally get “i === 2” (at number 5) in image. We then call the function (number 6), return “i”.

This is a function expression, and by assigning a function to a variable (in this case “printNumTwo”, we have “function-ified” (I sort of made up the term, not sure if there’s a technical term for this) the variable. What this means is the variable now holds a reference to the function, and this variable can later be called like any other function.

My understanding is it doesn’t really matter what “i” is at number 7 in the image (although “i” should have a value of 2 at that point). This is because all we’re saying is the variable “printNumTwo” now holds a reference to a function, which in turn returns “i”.

Then, “i++” gets executed because the body of the “if” statement has been executed, thus bringing “i” to 3. We’re now at number 9 in the image and we essentially console log whatever is the result of calling “printNumTwo()”, which is “return i”.

Since “i” has been incremented and is now 3, the console logs 3. Is this a correct understanding of what’s happening?

As for example #4 (provided before the challenge):

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

I’m guessing what’s happening here is more or less like in the earlier example. But since console.log(printNumTwo()) now prints 2, I’m not sure if this means “printNumTwo” doesn’t hold a reference to:

function() {
  return i;
}

Furthermore, I tried to fix the code by adding a line and it still doesn’t work:

let printNumTwo;
for (let i = 0; i < 3; i++) {
  if (i === 2) {
    let i = 2; // I added this, but i is still not defined.
    printNumTwo = function() {
      return i;
    };
  }
}
console.log(printNumTwo()); // Console: 2
console.log(i); // Console: i is not defined

Here, console.log(i) still leads to “i is not defined”, how would I go about fixing this?

Thanks so much, and sorry for the long post.

For the var example, the first thing that happens is the var declaration.
After that the for loop begins.
The last thing that happens is the log line actually.

By the time you get down to the log, the printNumberTwo variable is already assigned the function printNumberTwo whose job is to return the value of i at that moment. (The let version order is the same but in the let version the value of i is unique because there are three different i’s and the function is concerned with the value of the i when it was created as a 2. There are other i’s who are 0 and 1 but the function was made to use the specific one whose value was 2)


To make a variable defined outside of the loop using let, you just have to declare that variable in the appropriate scope. (So somewhere above the loop…)
1 Like

Hey pal, I’m not an expert but I think I can help you sort this out.

First of all, I’m not sure wether JavaScript gets executed sequentially, like in a cascade manner as languages like C or Java does. For all I know it is an interpreted language so I’m not sure if it is correct to think it in steps but here’s how I get it:

  1. var printNumTwo gets declared.
  2. for loop executes.
    2.1 var i get declared and initialized.
    2.2 Eventually, printNumTwo is assigned a function.
  3. You’ll print to the console whatever the variable function returns.

Now the key difference between example 3 and 4 is how the i inside the for is getting declared. Check that in ex 3 it is using a var and in ex 4 is using a let.
When you declare a variable inside a for loop or a function, it is said that it lives inside that scope { }, so outisde of it you can no longer reach it. This is the case when variables are declared using let, and that is why on ex 4 you cannot print the variable i; after the for loop finished executing it is no longer available, and that is why printNumTwo holds the last value of i, that is 2. Whereas, if you declare a variable using var it is said that is has a global scope, so its value is not reduced to the for loop but you can access it even after the for loop has finished executing. That is why even after printNumTwo gets assigned the function that returns i, after that lines gets executed i++ gets done and eventually when you call the function you get that 3.

1 Like

That part I must say sounds incorrect?

If the loop was longer say it went up to 4,
In the let version, the printNumberTwo would hold the same function (which returns 2 as that was the value of the unique i variable when the function was created and assigned to the variable)

2 Likes

Oh, didn’t realized that, thanks for pointing it out!!

So basically you are just assingning the following?

printNumTwo = function() {
  return 2;
}
2 Likes

Hi hbar1st,

Thanks so much for the explanation. This is a real eye-opener. I got the order of execution completely wrong.

I always thought function calls were executed first, i.e. “printNumTwo()”. My thinking is, if nothing is being asked of the “for” loop, why would it start executing? But that’s incorrect as you have pointed out.

I think my confusion stems from the fact that I’m used to seeing “for” loops being inside functions.

Usually I’d see a function being called, and then the “for” loop inside the function would run. I’ve been studying from a book and I think most of the examples I’ve seen are like that (I don’t want to fault the book though, this is just my incorrect understanding).

What’s interesting is this time, the “for” loop is not inside a function, and is executed right after the var declaration.

So I’ve written out the steps again, could you confirm whether this is correct? Thanks in advance.

I have “i++” at number 8 but I guess it increments after each loop. I guess what I mean is when (i === 2) then the function is called, which returns the value of variable “i”.

Would it be accurate to now say “printNumTwo” is a variable that holds a reference to the function, which returns “i”? After which, we have i++, and since “i” is now not less than 3, we exit the “for” loop and then go on to call “printNumTwo()” (number 9), then we console log it.

Am I describing what’s going on accurately?

As for example #4 with “let”, sorry I don’t quite follow what you mean there are three different “i” variables. Are you saying each time the “for” loop is run, when i === 0, i === 1, and i === 2, each of those "i"s are different variables?

In contrast, would it be accurate to say in the var example, although the “i” gets iterated, so it starts with i === 0, i === 1, and i === 2, those are all treated as the same variable but having different values at different times? Whereas in the “let” example, there are actually 3 separate distinct “i” variables?

Sorry for the long post, really trying to get my head around this, very much appreciate your help, thanks again.

Hey, thanks so much for the response.

You’re right, the order of execution does start with the var declaration, then the “for” loop etc. I can’t believe I got something so basic completely wrong :flushed:.

What you are saying makes sense, now I need some time to let it all sink in. I also saw the later comment from hbar1st commenting on your post, I need to digest all that info, thanks again, appreciate it.

yes that’s what that means. The var variables are all declared before anything else happens even though they seemingly are listed in different places in the program (so actually all the vars, even the var i are ‘setup’ or ‘declared’ first by whoever is processing this code - whatever js engine that is). So your order would have to account for this.
The vars become global if they are not within a function (if they are declared within a function they are scoped within that function, but this example here, all the vars are not inside functions so they are setup first by the js engine reading this code)

The initialization of the vars happens in a step sometime after the declaration (depending on the code in this case).

For the let i in the for loop, yes the explanation in the fCC exercise is quite clear I think. Each time you loop, you are essentially making a brand new variable called i with a brand new value.
(unlike the var i which was globally scoped and each time you looped would itself change its value)

I am not an experienced JS coder either…so I cannot give you a detailed explanation of which step happens first other than the above which is how far I have delved into this via the curriculum. So the only correction to your image that I feel fairly sure of is that the actual var declarations (printNumTwo and i) are both done first. The value i gets in the loop is done when the loop executes sometime later. (and yes the log is at the end given its location)

I do hope you can make sense of this exercise at least with this explanation.

ps.

yes that looks correct to me.

1 Like

Thank you so much!!! Appreciate it!!! :star_struck:

1 Like