Hoisting in JavaScript

Hoisting in JavaScript

Hoisting is a special behavior of the JavaScript interpreter. Hoisting means that function and variable declarations are moved to the top of their containing scope.

Variables Hoisting

In JavaScript, variables are declared using let, const, and var. All of them are hoisted, but their behavior differs.

When we attempt to access a variable before it's defined using var, we receive undefined, indicating that the variable is declared but not yet assigned a value.

Example:

console.log(name); // undefined
var name = "Murali";

In the above example, the variable name is declared at the top with the default value undefined. Its value is assigned only when the execution of the code reaches the variable assignment line.

However, when we try to access a variable before it's defined using let or const, we get a reference error stating that the variable cannot be accessed before initialization. This means the variable has been declared at the top, but no default value is assigned to it before its initialization. This behavior of inaccessibility of a variable when declared at the top using let and const is known as the Temporal Dead Zone (TDZ).

Example:

console.log(name); // ReferenceError: Cannot access 'name' before initialization
console.log(age); // ReferenceError: Cannot access 'age' before initialization
let name = "Murali";
const age = 23;

In this example, accessing name and age before their initialization results in a reference error.

Function Hoisting

In function hoisting, functions are declared at the top of their respective scope. This behavior allows functions to be executed even before the line at which they are defined.

Example:

const result = sum(4, 3);
console.log(result); // 7
function sum(a, b) {
    return a + b;
}

In this example, the function sum is invoked before its declaration, but it still works due to hoisting.

const result = multiply(4, 5);
console.log(result); // ReferenceError: Cannot access 'multiply' before initialization
const multiply = (a, b) => a * b;

Here, the code will throw an error because multiply is a variable hoisted to the top and initialized with an arrow function. Since value initialization occurs only when the code execution reaches the initialization line, accessing multiply before that line leads to a Reference Error.

If a function and a variable with "var" with the same name are declared and initialized in any order, what would be logged if we access the variable type before initialization?

Example:

console.log(typeof multiply); // function
function multiply(a, b) {
    return a * b;
}
var multiply = 5;
console.log(typeof multiply); // number

In this scenario, the function multiply is hoisted and initialized at the top, while the variable multiply is only declared at the top and initialized with the default value undefined. Therefore, when we log the type before initialization, it logs function. After initialization, it logs the respective type of the variable, which is number. Note that this behavior does not apply to arrow functions due to their lexical scoping.

Class Hoisting

In JavaScript, classes are also hoisted to the top of their scope. If we attempt to access a class via object creation before its initialization, we encounter a reference error stating "cannot access class before initialization."

Example:

const person = new Human("Murali"); // ReferenceError: Cannot access 'Human' before initialization
class Human {
    constructor(name) {
        this.name = name;
    }
}

In the above example, trying to create an instance of the Human class before its declaration will result in a reference error.

Before ES6, classes were not supported in JavaScript, so developers used functions (not arrow functions) to mimic the behavior of classes. To add new methods to such "classes" the prototype chain was utilized.

The old way to define the Human "class" would be:

var Human = function(name) {
    this.name = name;
};
Human.prototype.age = function(age) {
    this.age = age;
}

Therefore, class hoisting is similar to variable hoisting, where variables are declared at the top, and initialization happens at the line of execution. However, with classes, it's important to ensure that they are fully initialized before use, as attempting to access them prematurely will result in errors.

I hope you, as a reader, have gained a complete understanding of hoisting in JavaScript. If you feel that this blog has helped you grasp the concept of hoisting, please share it as much as possible.