ECMAScript 6 - New Feature - Overview And Comparison - Var Vs Let

Introduction

 
Let's talk about var first. Var in JavaScript works differently than similar keywords in other languages. Variables defined with var are hoisted on the top and we can use them before they are declared. 
  1. studentName = "Jake"// we can use studentName here     
  2. var studentName;   
Let me give you some pointers here about JavaScript Hoisting. 
 
Hoisting is JavaScript's default behavior where all variable declarations with the var keyword in a function are placed on the top of that function. We can prove this behavior by taking some more examples. 
  1. function favoriteFood(name){    
  2. if(name === "Charlie"){    
  3.    var food = "burger";    
  4. }    
  5. else    
  6. {    
  7.    var food = "I haven't the foggiest idea."    
  8. }    
  9. return food;    
  10. }   
Many of us might expect that it would return undefined or it would throw some warning or errors as the food variable is defined more than once.
 
But in case of hoisting, only one declaration of any given variable is hoisted to the top of the function, and any other declarations of the given variable are ignored.
 
After hoisting, this function should look like this.
  1. function favoriteFood(name){    
  2. var food;    
  3. if(name === "Charlie"){    
  4.    food = "burger";    
  5. }    
  6. else    
  7. {    
  8.    food = "I haven't the foggiest idea."    
  9. }    
  10. return food;    
  11. }   
As we can see in the above-given example, the declaration of variable food is moved to the top of the function, and only once.
 
Here is one more interesting example.
  1. function favoriteFood(name){    
  2. if(name === "Charlie"){    
  3.    food = "burger";    
  4. }    
  5. else    
  6.   {    
  7.       food = "I haven't the foggiest idea."    
  8.    }    
  9. return food;    
  10. var food;    
  11. }   
As you can see, we moved the declaration of food down to the bottom of the function.
 
It's not a recommended practice because it's bemusing. But it works because of hoisting. This code will still work as expected even though it looks like the declaration of food is blocked by the return statement and will never be reached.
 
The next important thing to understand about var is scope. The var keyword uses a functional scope.
  1. function testVariableScope {  
  2.  var greeting = "Good Morning!"; {  
  3.   var greeting = "Good Afternoon!";  
  4.  } {  
  5.   var greeting = "Good Evening!";  
  6.  }  
  7.  return greeting;  
This function will return "Good Evening" because of the functional scope of the var variable. If it had block scope it would return "Good Morning"!
 
Let's talk about the new ES6 keyword let,
 
As we saw, var uses hoisting and function scope whereas let doesn't use hoisting and uses block-scope. So what does that mean? Well, let's go back to our earlier examples, and change each var keyword to let. 
  1. function favoriteFood(name){    
  2. if(name === "Charlie"){    
  3.    let food = "burger";    
  4. }    
  5. else    
  6. {    
  7.    let food = "I haven't the foggiest idea."    
  8. }    
  9. return food;    
  10. }   
Now TypeScript gives us an error, it cannot find the name food. It's because let keyword in ES6 is block-scoped. Blocks are the closest containing set of curly braces.  
 
With let, the first food variable is only scoped to if statement curly braces and the second food variable is only scoped to else curly braces. The final food doesn't reference anything at all, which is why TypeScript gives us an error.
 
Let's fix this problem by adding a declaration to the top.
  1. function favoriteFood(name) {  
  2.  let food;  
  3.  if (name === "Charlie") {  
  4.   let food = "burger";  
  5.  } else {  
  6.   let food = "I haven't the foggiest idea."  
  7.  }  
  8.  return food;  
Now, as per the nature of block scope of let, we now have declared three variables in different block scopes. And, this function will always return undefined because the values are only set on the variable scoped to the blocks, not the one declared at the top of the function, which actually gets returned.
  
To set it straight, we need to remove the let keyword in each branch. Now there's one food variable that exists throughout the function and it'll work as intended.
  1. function favoriteFood(name){    
  2. let food;    
  3. if(name === "Charlie"){    
  4.    food = "burger";    
  5. }    
  6. else    
  7. {    
  8.    food = "I haven't the foggiest idea."    
  9. }    
  10. return food;    
  11. }   
The second major difference from var is that the let keyword doesn't hoist.
 
To see this in action let's reuse the existing example where we declared the variable after the return statement. 
  1. function favoriteFood(name){    
  2. if(name === "Charlie"){    
  3.    food = "burger";    
  4. }    
  5. else    
  6. {    
  7.    food = "I haven't the foggiest idea."    
  8. }    
  9. return food;    
  10. let food;    
  11. }   
Because of hoisting, this above-given code worked fine when using var. But TypeScript gives us an error every time we reference food and error goes like Block-scoped variable food used before its declaration. 
 
The reason for this error is because variables declared using let are not hoisted. So, we can't use a variable declared with let until after the let keyword has been hit. Because of hoisting it's fine to re-declare a variable with the var keyword inside a scope.
 

Summary

 
The var keywords are hoisted to the top of the scope and the lines are treated as assignments. However, with let re-declaring, a variable in the same scope becomes a duplicate identifier error. This can be useful to identify possible bugs in your program.