Tell us what’s happening:
In the ES6 challenges, the sample code shows that can use let
to assign values to variables in a function at the time we define the function. This is unlike var
, which assigns values at the time that we run the function.
Do you know why let
works this way?
I think I understand the other properties of let
, where you can only assign a variable once per block/statement/expression, and where its scope is local to the block/statement/expression, but I don’t understand how that causes let
to assign values to functions at the time when they’re defined.
Can you explain what causes this?
Thank you!
Your code so far
// This is a slight variation on the sample code
'use strict';
var printNumTwo;
for (let i = 0; i < 5; 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/72.0.3626.119 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
The only difference that let
has from var
is that var
has the scope of the entire function it’s defined in, whereas let
has the smaller scope of the enclosung block (such as an if
condition, or a loop). If one uses let
at the top level of a function, it’s exactly the same as var
.
It’s not evaluated at the time of definition: If it were, this would result in console output without even calling foo()
. You’re also perfectly able to redefine variables defined with let
; it’s const
that doesn’t allow for it.
function noisyVal() {
console.log("Hey, look at me!");
return 123;
}
function foo() {
let x = noisyVal();
}
Thanks, Chuck. Can you help me understand why the sample code I shared will return the number 2, instead of 4?
I understand that if i
were a var instead of a let then the function would return 4.
But I don’t understand why let causes the function to return a 2.
In your loop, when i
is 2, you create an entirely new function that captures the value of i
in its enclosing scope at the time of definition, then bind that function to the printNumTwo
variable. This sort of “inner function” is called a closure, and it’s not a property of let
so much as how function definition works, by “snapshotting” the local variables in the outer scope at the time the outer scope exits.
Beyond showing simple counter/adder examples, it’s hard for me to explain closures in a single post, but thankfully I can stand on the shoulders of giants and point you at a SO post that does the job far better than I could:
Your example in particular is curious, since I would have expected it to take on the binding of i
in the loop, and therefore be set to 5, not 2. That actually does appear to be a particular behavior of let
over var
in loops, with each iteration getting a fresh binding rather than sharing the same one. Looks like I learned something from your question today 
Thank you, Chuck! This helps a lot!