var, let, and const - The Three Musketeers
Understanding the differences between var, let & const
Introduction
In JavaScript, you might have seen the variables being declared using the keywords var
, let
and const
. This can be confusing to understand when to use each or how one is different compared to the other.
Although the three keywords have similarities in syntax, they differ in their usage and scope. Let's break this down to understand each keyword better.
Prerequisites
We can understand the differences between these keywords if we are aware of the following:
- Scope
- Hoisting
- Temporal Dead Zone
Let's quickly look into each of them.
Scope
JavaScript has 3 types of scope:
- Block scope - Variables declared inside a { } block cannot be accessed from outside the block. This means if you declare a variable within an
if-else
block or afor
loop, you will not be able to access the variable outside the code block. - Local or Function scope - Variables declared within a JavaScript function, become local to the function. They are not accessible outside the function block.
- Global scope - A variable declared outside a function, becomes global and is accessible throughout the script.
Hoisting
Hoisting is a JavaScript mechanism where variables and function declarations are "hoisted" to the top of the current scope (to the top of the current script or the current function).
Check the below code. When we declare the functions and invoke them, we get the expected output.
function sayHi() {
console.log("Hi");
}
sayHi();
// Hi
But what if we try invoking them before defining them?
sayHi();
function sayHi() {
console.log("Hi");
}
// Hi
As you can see in the above example, the function sayHi is defined after it is used, yet no errors are thrown. This is because JavaScript is taking that function and essentially moving it to the top of the file, in a way.
What actually happens behind the scenes is that when compiling the code, the browser puts the function into memory before running the code. We will see more examples of this later.
TDZ - Temporal Dead Zone
A temporal dead zone (TDZ) is the area of a block where a variable is inaccessible until the moment it is completely initialized with a value.
If this seems confusing, hold on tight! We will get there in a bit!
Alright, let's dive deeper.
Understanding var
var
was the first keyword that was made available in JavaScript to declare variables. But unlike in most other programming languages, var
works differently based on how the variable that is created is scoped.
Scope of var
var
is globally-scoped or function-scoped, meaning, they can be accessed throughout the code if declared globally, or only within the function block when declared inside a function.
var - globally-scoped:
var message = "Hello!!";
function sayHi() {
console.log(message); //message is accessible inside the function
}
sayHi(); //Hello!!
var - function scoped
function sayHi() {
var a = "5";
console.log(a); //5
}
//throws an error as "a" is not accessible outside the function block
console.log(a); //a is not defined
sayHi();
Hoisting of var
var
variables are hoisted to the top of their scope and initialized with a value of undefined
.
Look at the code below. We are trying to log the variable message before it is declared. The output is undefined
.
console.log(message);
var message = "Hello!!";
//undefined
This can be interpreted as:
var message;
console.log(message); //undefined
message = "Hello!!";
var
can be redeclared.
Understanding let & const
let
and const
was introduced in ES6 as a way of declaring variables.
Scope of let & const
let
and const
are block-scoped. Variables declared inside a { } block cannot be accessed from outside the block.
{
let a = 10;
const b = 20;
console.log(a); //10
console.log(b); //20
}
console.log(a); //a is not defined
console.log(b); //b is not defined
Hoisting of let & const
Variables declared with let
and const
are also hoisted but, unlike var
, are not initialized with a default value. A ReferenceError will be thrown if a variable declared with let
or const
is read before it is initialized.
console.log(a);
let a = 4;
//Uncaught ReferenceError: Cannot access 'a' before initialization
On putting a debugger on line 1 of the above code, we see the below memory allocation to the variable a. But this is in a separate memory space and not the Global object, one which can be accessed only when a value is provided to the variable.
Here's a different scenario:
let a = 4;
console.log(a); //4
The variable is hoisted into the other memory space before the execution of the code. On initialisation, the variable is reassigned with the initialised value - in this case, 4 which is then logged as the output.
Let's now see what TDZ is:
A temporal dead zone is the area of a block (Script) where a variable (a) is inaccessible until the moment it is completely initialized with a value (a=4).
Did you figure it out yet?
A let or const variable is said to be in a "temporal dead zone" (TDZ) from the start of the block until code execution reaches the line where the variable is declared.
While inside the TDZ, the variable has not been initialized with a value, and any attempt to access it will result in a ReferenceError. The variable is initialized with a value when execution reaches the line of code where it was declared.
Re-Declaring JavaScript Variables
- A variable defined using
var
can be redeclared or reassigned with a new value.
var msg = "I can be redeclared!";
console.log(msg); //I can be redeclared!
var msg = "Redeclared value";
console.log(msg); //Redeclared value
msg = "Redefined value of the existing variable";
console.log(msg); //Redefined value of the existing variable
- A variable defined with let cannot be redeclared but can be reassigned with a new value.
let msg = "I cannot be redeclared";
console.log(msg);
//I cannot be redeclared
msg = "However, I can be redefined!";
console.log(msg);
//However, I can be redefined!
let msg = "redeclaration throws an error here";
console.log(msg);
// SyntaxError: /src/index.js: Identifier 'msg' has already been declared
- A variable defined with const must be assigned a value when they are declared and cannot be redeclared or reassigned.
const msg = "I cannot be redeclared or redefined";
console.log(msg)
//I cannot be redeclared or redefined
msg = "Reassigning throws an error";
console.log(msg)
// Uncaught TypeError: Assignment to constant variable.
const msg = "Redeclaration throws an error"
console.log(msg)
// Uncaught SyntaxError: Identifier 'msg' has already been declared
Conclusion
Now that you know the differences between var
, let
and const
, when should you use them?
It is recommended that you always use const
when you don't have to reassign a value to the variable and use let
if there is a need to reassign a variable. It is best to avoid using var
as its behaviour varies as per the scope, which can lead to unnecessary problems with your code.
That's all, folks! Thank you for sticking to the end, you're a real one! Do let me know your thoughts on this blog post and share it with your folks if you found it helpful!