A dive to Hoisting in JavaScript

A dive to Hoisting in JavaScript

Hoisting has been one of the confusing and misunderstood concepts in JavaScript to beginners and many advanced developers. In this article, we will dive into Hoisting, how it works and the pros and cons attached to it.

What is Hoisting

Hoisting is the moving up of all variable declarations, functions, and classes to the top of their scope by the JavaScript Interpreter before being executed. Some variables and functions can be accessed before they’re declared, This makes the code cleaner and readable by separating the initialization from where they are called.

Variable in JavaScript

Before diving into Hoisting, let's first understand how variables are declared and assigned in JavaScript.

Variables in JavaScript are declared using var, let and const keywords (const and let are ES6 variables introduced in 2015). The const variable can not be reassigned in the code unlike the var and let variable.

Examples of variable declaration:

// Variable Declaration
var myName;
let age;

Variables are assigned using the assignment operator( = ):

var myName;
let age;
// variable declaration

myName = "sam";
age = 24;
// variable assignment

Screenshot from 2022-01-21 12-01-54.png

The image above shows that the const keyword cant be declared or re-assigned.

But in most cases, variables are declared and assigned in a single line (e.g the const variable).

var myName = "Sam";
let age = 24;
const hobby = "Coding";

Var Variable Hoisting

console.log(myName);
var myName;
myName = "Sam";

// Log
undefined

From the code above, variables declared with var are actually hoisted but their initial value is set to undefined.

Let and Const Hoisting

// variables declared with let and const
console.log(age);
console.log(hobby);

let age = 24;
const hobby = "coding";

// Log
Uncaught ReferenceError: Cannot access 'age' before initialization
Uncaught ReferenceError: Cannot access 'hobby' before initialization

From the code above, variables declared with let and const throws an error because they are in the TDZ(Temporal Dead Zone) and can’t be used or accessed before initialization, thus hoisted technically.

What is TDZ?

The TDZ is known as a Temporary Dead Zone. This is the space between the beginning of the current scope to the line or point where the variable declared with let or const is initialized, be it in a global or function scope.

TDZ of let

// TDZ of let
//------------------------>the TDZ starts here
console.log(age);//------->TDZ
//------------------------>TDZ
//------------------------>TDZ
let age = 24;//----------------->TDZ ends here

TDZ of const

//TDZ of const
//--------------------------->The TDZ starts here
console.log(hobby);//-------->TDZ  
 //-------------------------->TDZ
//--------------------------->TDZ
const hobby = "coding"; //--------->TDZ ends here

Why TDZ?

The TDZ was introduced in ES6 (ECMAScript 6) alongside let and const and one of the primary reasons for its introduction was to Avoid, Prevent and Catch errors and bugs. TDZ was introduced before using the var keyword to set initial values created bugs in large javaScript codebases. TDZs also prevent the const keyword from setting an initial value of undefined and reassigned after declaring it in another variable in a codebase.

How Functions are hoisted

Functions are hoisted slightly differently from variables in JavaScript. There are three (3) ways of creating functions in JavaScript namely Function declaration, Function Expressions, and Arrow Functions.

Hoisting with Function Declaration

// Hoisting in Function Declarations
greetDeclaration();

function greetDeclaration() {
  console.log("Hello world from Hoisting in Function Declaration");
}

// Log
Hello world from Hoisting in Function Declaration

In the above code, the function was executed smoothly without errors. This is because Function declarations are hoisted, and their initial value is set to the Actual Function.

Function Expression

Function Expressions are normal functions that are stored or assigned to a variable.

// Hoisting in Function Expression
greetExpression();

const greetExpression = function () {
  console.log("Hello world form Hoisting in Function Expression");
};

// Log
Uncaught ReferenceError: Cannot access 'greetExpression' before initialization

The code above throws a Reference uninitialized error because the JavaScript Interpreter treats the functions as a variable. Since it's declared with a const, it is expected to get the same result as a variable declared with const. Thus hoisted technically but cant be used or accessed before initialization.

Arrow Functions

Arrow functions, also known as the Anonymous function, are normal variables that store a function.

// Hoisting in Function Expression
greetArrow();

const greetArrow = () => console.log("Hello world form Hoisting in Function Arrow");

// Log
Uncaught ReferenceError: Cannot access 'greetArrow' before initialization

The code above throws a Reference uninitialized error because it’s an ES6 function, and since ES6 was released to help prevent bugs, this makes arrow functions be hoisted uninitialized instead of undefined like var.

Hoisting of Function Expression declared with var

// Function Expression declared with var
greetExpression();

var greetExpression = function () {
  console.log("Hello world form Hoisting in Function Expression");
};

// Logs
Uncaught TypeError: greetExpression is not a function

Functions declared with var throws a TypeError because the JavaScript Interpreter sets the function to undefined, thus making the whole function return undefined.

Hoisting of Arrow Function declared with var

//Arrow Function declared with var
greetArrow(); 

var greetArrow = () =>
  console.log("Hello world form Hoisting in Function Expression");

// Log
Uncaught TypeError: greetArrow is not a function

Like the Function declaration, Arrow Functions declared with var throws a TypeError because the JavaScript Interpreter sets the function to undefined, thus making the whole function return undefined.

Hoisting in ES6 Classes

Classes in JavaScript are a blueprint, framework, or template for creating objects in ES6 JavaScript. They are also known as Syntactical sugar for creating objects. Classes can be created using declarations or expressions, just like functions.

Hoisting in Class Declarations

var car = new Car();
car.color = "Jane";

console.log(car); 

class Car {
  constructor(color) {
    this.color = color;
  }
}

// Log
// Uncaught ReferenceError: Cannot access 'Car' before initialization

Hoisting in class declarations throws a ReferenceError which is similar hoisting a variable declared with let or const before it is initialized in our code.

Hoisting in Class Expressions

//Class Experssions
const instance = new Food();

console.log(instance.order());  

const Food = class {   
  constructor() {}
  order() {
    return 'What dish do you want?!';
  }
};   

//Log
Uncaught ReferenceError: Cannot access 'Food' before initialization

Class Expressions also experience the const treatment like in functions. They can’t be hoisted to the actual object or to undefined. Thus they are uninitialized.

Hoisting in Class Expressions declared with var

//Class Experssions declared with var
const instance = new Food();

console.log(instance.order());  

var Food = class {   //declared with var
  constructor() {}
  order() {
    return 'What dish do you want?!';
  }
};   

//Log
Uncaught TypeError: Food is not a constructor

Hoisting in Classes declared with var returns a TypeError just like in functions. This is caused by the JavaScript Interpreter setting the class to undefined.

Hoisting Table

This is a comprehensive list hoisting in all variable declarations, expressions, functions, and classes.

Screenshot from 2022-01-23 21-17-38.png

Conclusion

In this article, we looked at Hoisting, what it is, and the way it works with variables, functions, and classes. How using var can be the source of bugs in large JavaScript codebases and how ES6 modules like let and const might be better alternatives and can serve as a workaround to var. I hope that you finally understand what Hoisting is, it’s use cases and why it is important in JavaScript.