How do we declare variables in JavaScript?
Using let, const and var.
ES6 introduced let and const to overcome some limitations of var. Generally the questions around this topic sets the flow of your interview.
P.S. : Please watch the video for better explanation. Javascript Interview Questions ( Var, Let and Const ) This is written format for the video incase you want to follow along the tutorial.
Contents
Scope
variable shadowing
variable declaration
variable declaration without initialization
Reinitialisation of variables
How execution context works?
Hoisting & Temporal Dead zone
Scope
** What is Scope?** Scope is a certain section/region of the program where a defined variable has it's existence and beyond that it cannot be accessed.
Three types of Scope
Global scope
Functional scope
Block scope
var a=5; // global scope
Why are talking about scope? Well var is functional scope, let and const is block scoped
Let's see how?
{
var a=5
}
console.log(a); // 5 -- a is accessible outside the block ✅
{
let a=5;
}
console.log(a) // ReferenceError: a is not defined ❌
{
const a=5;
}
console.log(a); // ReferenceError: a is not defined ❌
How can we make it work?
{
let a=5;
console.log(a);//5
}
{
const a=5;
console.log(a);//5
}
You see why let and const are block scoped because their scope is within a block meaning a block of statements.
Variable shadowing
let and const are block scoped and from there we get the concept of shadowing.
Let's check out this example
function test() {
let a = 'Hello';
if (true) {
let a = 'Bye';
console.log(a); -- 1.❓
}
console.log(a); -- 2 ❓
}
test();
Let's solve this problem. Can you see a being declared in two different regions. What do you think 1. and 2. will print?
function test() {
let a = 'Hello';
if (true) {
let a = 'Bye'; // New value assigned
console.log(a); 1. Bye // a shadows the a defined outside the block scope and prints "Bye"
}
console.log(a); 2.Hello // it will print a which is in the available scope
}
test();
While variable shadowing it shouldn't cross the boundary of the scope.
It means we can shadow var using let but not the opposite because if we try to do so let using var we will go into illegal shadowing.
Let's check in an example
function func() {
var a = 'Hello';
let b = 'Roadside coder';
if (true) {
let a = 'Hi'; // Legal Shadowing
var b = 'Bye'; // Illegal Shadowing
console.log(a); 1.Hi ✅
console.log(b); 2. SyntaxError: Identifier 'b' has already been declared ❌
}
}
test();
Let's see variable a and b being declared in different scope. If we shadow var with let it is legal shadowing and will print "Hi" where if you see 2. output It gives SyntaxError since we are trying to shadow let with var which is known as Illegal shadowing.
Declaration
Can you declare a variable multiple times? Let's see.
var a;
var a; ✅
let a;
let a;❌ SyntaxError: Identifier 'a' has already been declared
const a;
const a; ❌ SyntaxError: Missing initializer in const declaration
Conclusion : We can declare var as many times as we want in the same scope but we cannot declare let and const in the same scope multiple times. Example :👇🏼
let a;
{
let a;
}
Declaration without initialization
What if you declare a variable without any value? Let's see.
var a; ✅
let a; ✅
const a; ❌ SyntaxError: Missing initializer in const declaration -- you need to intialise a const while declaring it
Re-initialization
What if you initialize a different value to the same variable? Let's see.
var a=5;
a=6; ✅
let a=7;
a=10; ✅
const a=10;
a=12; ❌ TypeError: Assignment to constant variable.
const gives an error since you can not reinitialize a const variable where as you can do it with a let and const variable.
Hoisting
Before we talk about Hoisting let's see How does JS execution context works?
Let's see the working of execution context using an example 👇🏼
let a=10;
function multiply(a){
return a*20;
}
let b= multiply(20);
console.log(b);
JavaScript executes the following snippet in 2 phases line by line.
There are 2 phases :
Creation phase
Execution phase
***Creation phase ***
It creates a global or window object
It setups a memory heap for storing functions and variables references. It takes all variables and functions to store inside the window object.
It Initializes variables and functions. For variables it initializes with undefined and for functions declaration it stores the complete function body and stores inside the window object.
Execution phase
JS engine executes the code line by line. It assigns values to variables and executes the function calls.
P.S. : For every function it creates a new execution context
It also uses call stack to keep track of the function calls
What is Hoisting?
During the creation phase JS engines moves the declaration of variables and function to the top of the code which is know as hoisting.
console.log(count); // undefined
var count=4;
It gives undefined because of hoisting.
During creation phase it creates memory space for count variable and assigns a value undefined. Now during execution phase it sees the variable count and prints undefined.
**Are let and const also hoisted? **
console.log(count);
let count=6; // ReferenceError : cannot access 'count' before initialization
Yes ! they are hoisted but in temporal dead zone.
So let overcomes the flaws of var generally.
What is Temporal dead zone?
It is the time between declaration and initialization of let and const variables.
Now we come to end of this blog. Hope you had a great read. Got suggestions? Drop a personal note.
Piyush Agarwal (RoadsideCoder)
Follow Roadside Coder on Youtube for more such great videos on JavaScript and React.