ES2015 (or ES6) introduced two new ways to create variables, let and const. But before we actually dive into the differences between varlet, and const, there are some prerequisites you need to know first. They are variable declarations vs initialization, scope (specifically function scope), and hoisting.

Var

Scope essentially means where these variables are available for use. vardeclarations are globally scoped or function/locally scoped. It is globally scoped when a var variable is declared outside a function. This means that any variable that is declared with var outside a function block is available for use in the whole window. var is function scoped when it is declared within a function. This means that it is available and can be accessed only within that function.

function discountPrices (prices, discount) {   
console.log(discounted) // undefined
var discounted = []
for (var i = 0; i < prices.length; i++) {
var discountedPrice = prices[i] * (1 - discount)
var finalPrice = Math.round(discountedPrice * 100) / 100
discounted.push(finalPrice)
}
console.log(i)
console.log(discountedPrice) // 150
console.log(finalPrice) // 150
return discounted
}

let

let is preferred for variable declaration now. It's no surprise as it comes as an improvement to the var declarations. It also solves this problem that was raised in the last subheading. Let's consider why this is so.

let is block scoped

A block is chunk of code bounded by {}. A block lives in curly braces. Anything within curly braces is a block. So a variable declared in a block with the let is only available for use within that block. Let me explain this with an example.

function discountPrices (prices, discount) {
console.log(discounted) // ❌ ReferenceError
let discounted = []

for (let i = 0; i < prices.length; i++) {
let discountedPrice = prices[i] * (1 - discount)
let finalPrice = Math.round(discountedPrice * 100) / 100
discounted.push(finalPrice)
}
console.log(i) // Error
console.log(discountedPrice) // Error
console.log(finalPrice) // Error
return discounted
}

const

Variables declared with the const maintain constant values. const declarations share some similarities with let declarations.

Like let declarations, const declarations can only be accessed within the block it was declared.

This means that the value of a variable declared with const remains the same within its scope. It cannot be updated or re-declared.

Block scoping means that you can shadow variables within a function:

function func() {
const foo = 5;
if (···) {
const foo = 10; // shadows outer foo
console.log(foo); // 10
}
console.log(foo); // 5
}

Constants, variables created by const, are immutable – you can’t assign different values to them:

const foo = 'abc'; 
foo = 'def'; // TypeError

const only means that a variable always has the same value, but it does not mean that the value itself is or becomes immutable. For example, obj is a constant, but the value it points to is mutable – we can add a property to it:

const obj = {}; 
obj.prop = 123;
console.log(obj.prop); // 123