Let Keyword Confusion and Closure

Tell us what’s happening:
In the code below, the variable i is created three times with different values (0, 1, 2) in each iteration of the for loop and I have some questions.

  1. How come the variable i is created three different time when in for loop we initialize it only once?
  2. When the variable is created again in second or third iteration of the loop, how does it know to update to a new value?
  3. When we call printNumTwo function reference variable, we are able to access the variable i local to the if block of the function even after the loop has ended and we now have a closure situation, right? My question is when does JavaScript create a closure in general? Does it happen only when a function is declared inside another function or it could happen in a situation like this?

Your code so far


'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"

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 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/

Premise: when you declare a local variable, that value “exists” only inside that block of code, once executed that variable is thrown away since it’s not needed anymore.

example:

function add() {
  let x = 0
  return x + 1
}

add() // returns 1
add() // still return 1, since x lives only inside add
console.log(x) // ReferenceError: x is not defined

A closure is a way to keep reference of a local, privare variable, persistent even after the block has been executed.
This means that we can expect any variable that was in scope to still holds its value, even if we call that function from a totally different context.

This is usually done by creating a function inside another function, so that your “inner” function remembers the value of the “outer” function even after has been executed

example

// note that this function expects a param
// declare a local variable that is a function
// and return the function
function makeAdd(x) {
  let add = function(y) {
    return x + y
  }
  return add
}

let startWithTwo = makeAdd(2) // Function
let addTwo = startWithTwo(2) // 4
let addSixInstead = startWithTwo(6) // 8

As you can see, the last two functions “remember” the value of 2 passed at the beginning and works correctly. So the value has not been thrown away after the first execution


The example you posted show the interaction with the let statement that declares a local scoped variable.
That’s why
printNumTwo works since it was declared at the top of the file, so it can be accessed yet it remembers the value of i
i is not defined since exists only inside the for loop. After that loop executes the variable is thrown away.

Hope this helps :+1:

1 Like

Clear this up for me - In the code above, when we call printNumTwo, the function is accessing the value of i, which is 2 at the time, when the if block is executed, right? Does this mean that behavior of let keyword cascades down to the code blocks below?

That has to do with how block scope works.
An inner function can access the values of the outer function it was declared in.

function outside() {
  let x = 0
  function inside() {
    let y = 1
    // has access to both x and y
  }
  // here we are out of "inside" scope, y cannot be accessed
}

And that’s why printNumTwo works and is still able to keep a reference of i.

So, inside the if block the value of i is 2 and when we call the function within that block, it references that value, right? Since it is remembers the variables even after the loop and block has executed, can we call that closure?

Correct, because it’s made by the combination between a function and the scope it was created in.

Ok, I get it now. Thank you for the help.