Today I Learned: The Difference Between Var and Let in ES6
With ES6 we now have access to a very cool keyword, let. I know you are thinking, ok, but what is so great about it? Why would I use it over var? Well, this article is going to explain to you just that.
I know for a fact that many of us javascript developers have seen this before and scratched our heads.
Hoisting
var outerFunction = function() {
var foo = 7;
var inner = function(){
console.log(foo) //undefined
var foo = 8;
}
inner();
}outerFunction();
You are sitting there wondering, why is foo undefined? I defined foo in the outer function yet it is undefined. Furthermore, I defined foo in the inner function. Shouldn’t foo be equal to 7 or even 8? The answer is no. This is what’s actually is going on.
var outerFunction = function() {
var foo = 7;
var inner = function(){
var foo;
console.log(foo)
foo = 8;
}
inner();
}outerFunction();
The declaration of foo is being “hoisted” to the top of the inner function’s scope. The key takeaway is declaration. It gets initialized later on in the function to 8. In reality this is what the above function looks like in javascript.
var outerFunction = function() {
var foo = 7; var inner = function(){
var foo; // declaration being hoisted
console.log(foo)
foo = 8;
}
inner();
}outerFunction();
The declaration of a variable, not the initialization, is “hoisted” to top of the scope.
We see that the declaration of foo is hoisted to the top of inner but its initialization occurs later on. This has left many of us wondering what the heck is going on.
Have no fear, let keyword is here! Let’s go ahead and convert all of the vars to lets and see what happens.
let outerFunction = function() {
let foo = 7;let inner = function(){
console.log(foo)
let foo = 8;
}
inner();
}outerFunction();
What do you think the output will be? In a sense, it is the same but this time instead of undefined we get: Uncaught ReferenceError: foo is not defined
Perfect! From this error message, we are able to identify where our problem lies. The declaration of foo is no longer hoisted to the top of its scope. It is declared and initialized in the same place. let is contained to its block scope. This is very useful and helps eliminate strange bugs. It no longer fails silently.
Ok, let’s look at a more interesting example right off of MDN’s documentation.
Scope
function varTest() {
var x = 31;
if (true) {
var x = 71; // same variable!
console.log(x); // 71
}
console.log(x); // 71
}
function letTest() {
let x = 31;
if (true) {
let x = 71; // different variable
console.log(x); // 71
}
console.log(x); // 31
}As we learned in our previous example, in function varTest, x is hoisted to the top of the function’s scope and declared. x is then later initialized twice. First, x is initialized to 31 and then to 71. x is essentially being declared twice as the same var. both x’s scope is that of the entire function not of the block and the function. This is why both declarations of x are hoisted to the top of the enclosing function.
In letTest, x declared outside of the if(true) block is hoisted, declared, and initialized in the first line, as evident by its scope (the entire function). the x declared with the let keyword inside of the if(true) block is not hoisted to the top of the scope but rather declared and initialized on the same line that it was declared as a completely different variable and is unique to its block scope. For this reason, x inside the if (true) section of the code = 71 and outside of the if true is = to 31. Each let x declaration is contained to its new scope, the entire function scope and the block scope. Previously, if declared with the var keyword the if(true) block scope would be ignored and both variables would be hoisted to the top of the function scope.
To cut a long story short, let now allows us to declare variables with “expected behavior”. With let, what you think a variable will do, it will most likely do. I know that is not a very technical explanation but, I hope it makes sense. All in all, I would definitely recommend favoring let over var. You will avoid a good deal of unexpected outcomes.
Thanks! — J