let & const in Javascript

In ES5 land we’ve been using the var keyword for years to declare variables, now with ES6 we can use let and const to declare variables.

What the heck is a variable anyway?
In programming a variable is a named value that can change over time.

var keyword
var name = 'Mark';   // variable declaration
console.log(name); // Mark
name = 'Peter'; // assign a new value to 'name'
console.log(name); // Peter

Cool, so why do we need more ways to declare variables?

When a variable is declared using var, it’s scope is tied to the execution context where it was declared. This means a variable is accessible inside the function scope it is declared. Sometimes you might desire this, most times you don’t.

var Example
var arr = [];
for(var i=0; i < 5; i++) {
arr.push(i)
}
console.log(arr) // [0, 1, 2, 3, 4]

Here the execution context for the variable “i” is the for-statement. The results of the logged array is satisfactory, we get the values pushed into the array incremented from “0”.

Let’s see the results when adding a setTimeout function inside our for-statement.

var arr = [];
for(var i=0; i < 5; i++) {
setTimeout(function(){
arr.push(i);
}, 100)
}
console.log(arr) // [5, 5, 5, 5, 5]

Our array is printing out the final value of “i” for each element inside the array. This is undesirable in our example. We expected “[0, 1, 2, 3, 4]”. The reason for this is because all loop iterations share the function scoped variable “i”, which has the final value “5”. Every time the for-loop run “i” is overwritten, eventually when setTimeout is run it receives the final value of “i” which is “5”.

let & const keywords

The let & const keywords allows us to declare block-scoped variables. 
This enables us to use variables inside a block and all nested sub-blocks.

let name = “Mark”;
const data = [];
block-statements Example
function printName() {              // start 1st block 
   if(2 > 1) {                      // start 1st sub-block
console.log('ES6');
} // end 1st sub-block
}                                   // end 1st block

Block-scope refers to all code inside curly brackets, not to be confused with an object literal. This code demonstrates two block statements. The first one is the function which is the parent-block, the sub-block is the if-statement.

let Example 1
function printName() {
let name = "Mark";
if(2 > 1) {
let name = "Peter";
console.log(name); // Peter
}
console.log(name); // Mark
}
let Example 2
for(let i=0; i < 5; i++) {
setTimeout(function(){
arr.push(i);
}, 100)
}
console.log(arr) // [0, 1, 2, 3, 4]

Here “Example 2” is returning the elements inside the array we expected. This is working because the let declaration is declaring a new “i” variable inside the block on each iteration of our for-loop run. Here setTimeout is also a sub-block and have access to variables created by it’s parent

const Example 1
const name = “Sam”;
name = "Mark" // TypeError

You can’t re-assign a const variable with a new value. This is not allowed. const is great for variables that will never be re-assigned inside your code.

const Example 2
const data = [];
data.push(1,2,3);
console.log(data); // [1,2,3]
data.pop();
console.log(data); // [1,2]

const variables are not truly immutable. Here we mutating the array, however assigning a new value to “data” using the assignment operator will throw a TypeError as we see in Example 1.

Final Thoughts:
Having adopted let and const inside codebases where I use ES6+ I have found it vary rare to use the var keyword when declaring variables.