21
NovHoisting in JavaScript: Variable Hoisting and Function Hoisting
JavaScript Hoisting
Hoisting in JavaScript is a feature that allows variables and functions to be used even before their declaration. This increases code flexibility and avoids "undefined" errors during program execution.
In this JavaScript tutorial, we'll discuss JavaScript hoisting, the types of JavaScript hoisting, i.e., variable and function hoisting, temporal dead zone, and more.
Read More: JavaScript Interview Questions and Answers (Fresher + Experience) |
What is Hoisting in JavaScript?
Hoisting is JavaScript's default behavior of moving the declarations of variables and functions on top of their containing scope at the time of compilation so that they can be accessed in that entire scope regardless of their declaration place. The JavaScript interpreter splits the declaration and assignment of variables and functions before any code execution.
To understand JavaScript Hoisting, you must be very well aware of the below two topics: |
Types of Hoisting in JavaScript
There are two types of JavaScript Hoisting:
- Variable Hoisting
- Function Hoisting
We'll understand both these types in detail in the below section.
1. Variable Hoisting in JavaScript
In JavaScript, we declare variables with keywords like var, let, and const. Hence, the hoisting behavior depends on the keyword usage. There's also a case where no such keywords are used to declare variables. Let's take a look:
1. Variable Hoisting With 'var'
When you declare a variable in JavaScript using the var keyword, the interpreter hoists it with the default value of undefined.
// use the message variable before declaration
console.log(greet);
// variable declaration using var keyword
var greet;
var msg
console.log(msg);
In the above code, the first line console.log(greet) output is undefined because greet is hoisted and given a default value. The above two lines are equivalent to the next two lines, where the variable msg is declared first and then printed.
Output
undefined
undefined
Remember that printing an undeclared variable will throw a ReferenceError.
// use the message variable before declaration
console.log(greet);
Output
console.log(greet);
^
ReferenceError: greet is not defined
Similarly, using a variable before assigning it with a value will throw a ReferenceError because no declaration is hoisted.
console.log(greet);
greet = "Welcome to ScholarHat"
Output
console.log(greet);
^
ReferenceError: greet is not defined
2. Variable Hoisting With 'let' and 'const'
When we declare a variable with 'let' or 'const,' it is hoisted on top without initializing it with any default value like 'undefined.' It gives a ReferenceError when you access an undeclared let or const variable.
// use the message variable before declaration
console.log(message);
// variable declaration using let keyword
let message;
In the above code, the variable message is declared with let and so is not assigned any default value when hoisted.
Output
console.log(message);
^
ReferenceError: Cannot access 'message' before initialization
As the variable is hoisted, the error shown is "Cannot access 'message' before initialization." If it wasn't hoisted, the error would have been "ReferenceError: message is not defined." This indicates that the let or const variable is initialized somewhere.
Temporal Dead Zone
We saw above that accessing undeclared let or const variable gives a ReferenceError. This is because of the temporal dead zone (TDZ). The temporal dead zone (TDZ) begins from the start of the scope of the variable until the variable is declared.
Example demonstrating Temporal Dead Zone in JavaScript
{
// Start of greet's TDZ
let msg = 'Welcome';
console.log(msg);
console.log(greet); // ReferenceError because greet is in the TDZ
let greet = 'Welcome'; // End of greet's TDZ
}
In the above code, we're accessing the variable "greet" in the temporal dead zone (TDZ).
Output
Welcome
/index.js:6
console.log(greet); // ReferenceError because greet is in the TDZ
3. Implicit Global Variables
We know that undeclared variables, when initialized, become global variables implicitly. Such implicitly global variables behave like variables declared with the var keyword.
function VariableHoisting() {
x = 80; // Implicit global variable
let y = 20;
}
VariableHoisting();
console.log(x);
console.log(y);
The variable x is an implicitly global variable; hence, it is accessed outside the function VariableHoisting(). The variable y is declared with the let keyword, and hence it becomes a local or block-scoped variable to the VariableHoisting() function. Therefore, accessing y outside the function results in ReferenceError.
Output
80
/index.js:7
console.log(y);
^
ReferenceError: y is not defined
2. Function hoisting in JavaScript
Like variable hoisting, where we can use the variables before the declaration, we can call the function before their definition.
Example of Function hoisting in JavaScript
// function call
greeting();
// function declaration
function greeting() {
console.log("Welcome to ScholarHat.");
}
The above code calls the greeting() function before its definition due to hoisting.
Output
Welcome to ScholarHat.
If you call a function that isn't declared, JavaScript gives ReferenceError.
greet();
Output
greet();
^
ReferenceError: greet is not defined
Function Expressions Hoisting in JavaScript
The JavaScript interpreter hoists only the function declaration and not function expressions like the variable assignments.
Example Illustrating Function Expressions are not hoisted in JavaScript.
// call greet() function before declaration
greet();
// function expression
var greet = function() { }
Output
greet();
^
TypeError: greet is not a function
// call greet() function before declaration
greet();
// function expression
let greet = function() { }
Output
greet();
^
ReferenceError: Cannot access 'greet' before initialization
In the above two codes, the function expression is assigned to the variable greet. When we try to call greet(), it shows TypeError and ReferenceError, respectively, depending on the scope of the variables.
Function-scoped Variable Hoisting in JavaScript
We'll understand the hoisting of variables inside the function with an example.
Example of Function-scoped Variable Hoisting
function greet() {
// use the variable message before declaration
console.log(message);
var message;
}
//function call
greet();
console.log(message);
In the above code, the message variable is hoisted to the top of the greet() function and becomes a local variable. Because its scope is limited to the function, it's not accessible outside the function.
Output
undefined
/index.js:11
console.log(message);
^
ReferenceError: message is not defined
JavaScript Initializations are Not Hoisted
JavaScript hoists the declaration to the top of the scope during the compilation phase. Does the variable initialization also get hoisted? No, the initialization remains at the same place where it's done.
Example
console.log(greet);
var greet = 'Welcome to ScholarHat';
Output
undefined
The above code is equivalent to:
var greet;
console.log(greet);
greet = 'Welcome to ScholarHat';
Output
undefined
Here, the value of the greet variable is undefined because it is printed without initializing it.
Summary
Hoisting is an important JavaScript concept that is often overlooked. One must try to avoid using variables before their declaration. The best practice is to declare and initialize variables before their usage. Hoisting can make your program tricky and cause problems. Therefore, it's advantageous to be aware of the hoisting phenomena and try to avoid them as much as possible. For more such important concepts, consider our JavaScript Programming Course.
Take our Javascript skill challenge to evaluate yourself!
In less than 5 minutes, with our skill challenge, you can identify your knowledge gaps and strengths in a given skill.