DEV Community

kris
kris

Posted on • Originally published at blog.bitsrc.io on

What is JavaScript Hoisting?

Learn to code better with a clearer understanding of JS hoisting

Hoisting is JS’s default behavior of defining all the declarations at the top of the scope before code execution. One of the benefits of hoisting is that it enables us to call functions before they appear in the code. JavaScript only hoists declarations, not initializations. You can find the official documentation here.

Tip : Turn reusable JS code into shared components with Bit (GitHub). Bit helps everyone build modular JavaScript applications , easily share components between projects and team, and build better & faster

Share reusable code components as a team · Bit

Understanding what exactly is JavaScript Hoisting

Variable declaration and initialization occur in the following sequence:

Declaration –> Initialization/Assignment –> Usage

// Variable lifecycle
let x; // Declaration
x = “hoisting”; // Assignment
console.log(x); // Usage

However, since JavaScript permits both declaration and initialization of variables simultaneously, this is the most used pattern:

let x = “hoisting”;

Most importantly, you should always remember that the JavaScript declares the variable first in the background. Then, initializing them. Thus, it is also good to know that the processing of variable declarations takes place before the execution of any code. However, until the execution of code assigning them takes place the undeclared variables do not exist in JavaScript.

Therefore, when the assignment is executed, a value assigned to an undeclared variable implicitly creates it as a global variable. This specifies that all undeclared variables are global variables.

// hoisting
function Hoisting(){
  x = 100;
  let y = 200;
}
Hoisting();
console.log(x); // 100
console.log(y); // Reference Error: y is not defined

In the above code sample, there is a function called Hoisting(). Thus, we have a variable which we didn’t declare using let/var/const and a let variable y. The assigning of the undeclared variable to the global scope is done by JavaScript. But for variable y, we get a ReferenceError.

Hosting in ES5

In ES5, we consider the var keyword. Hoisting with var is somewhat different in comparison to let/const. The example with var to see how hoisting works:

var num (global)
console.log(car); // undefined
var car = ‘Lamborgini’;

In the above code, when logging the variable name which was declared and assigned later than using it, the compiler gives an “undefined” result. This was not expected as we should have got ReferenceError as trying to use the car variable even before declaring it.

But the interpreter sees this differently, which is as follows:

//how interpreter sees the above code
var car;
console.log(car); // undefined
car = ‘Lamborgini’;

Hosting in Function scoped variable

Let’s learn how hoisting of function-scoped variables takes place with the following example:

//function scoped
function myFunc(){
  console.log(car);
  var car = ‘Lamborgini’;
}
myFunc(); // undefined

However, there is no difference as in comparison to the code where the declaration of the global variable takes place. The interpreter provides the result as “undefined”.

//function scoped
function myFunc(){
 var car;
 console.log(car);
 car = ‘Lamborgoni’;
}
myFunc(); // undefined

In order to mitigate this, we can make sure to declare and assign the variable at the same time, before using it. Thus, the code below shows the declaration at the top:

function myFunc(){
  var car = ‘Lamborgini’;
  console.log(car) // Lamborgini
}  
myFunc();

Hoisting in ES6

We can see the example below:

let num(global)
console.log(num);
let num = 003; // ReferencError: num is not defined

In the var keyword, we expect the output of the log to be undefined. However, since the let in es6 doesn’t take allow using undeclared variables, the interpreter throws a Reference error explicitly. This makes sure that we always declare our variable first.

The let and const Keywords.

Variables and constants declared with let or const are not hoisted!

JavaScript Initializations are Not Hoisted

JavaScript only hoists declarations, not initializations.

var a = “volkswagon”; // Initialize a
var b = “Lamborgini”; // Initialize b
elem = document.getElementById("car"); // Find an element
elem.innerHTML = a + " " + b; // Display a and b as volkswagon and lamborgini

In the above code, since the declaring of variables takes place before the results. As a result, the execution of the code prints the result of variable a and b.

var a = “i10”; // Initialize a
elem = document.getElementById("car"); // Find an element
elem.innerHTML = "a is " + a + “ and b is " + b; // Display a and b
var b = “Lamborgini”; // Initialize b

Result:
a is i10 and b is undefined

Hence, this is because only hoisting of the declaration (var b) takes place, not the initialization (= “Lamborgini”) to the top. Because of hoisting, b has been declared before it is used, but because initializations are not hoisted, the value of b is undefined.

Hoisting classes

JavaScript classes can be classified into two classes:

  • Class declarations
  • Class expressions

In Class declarations

They are much like function counterparts. Therefore, this means no hoisting of JavaScript class declarations. However, they remain uninitialized until evaluation. Thus, this effectively means that you have to declare a class before you can use it.

var car1 = new car();
car1.height = 5;
car1.weight = 500;
console.log(car1); // Output: ReferenceError: car is not defined
class car{
  constructor(height, weight) {
    this.height = height;
    this.weight = weight;
  }
}

In the above code, the reference error occurs. This is because, after initialization of the car1 variable, the defining of car class is takes place. To solve this error, we just need to define the car class before car1 initialization. This is hosting in the class declaration.

class car{
  constructor(height, weight) {
    this.height = height;
    this.weight = weight;
  }
}

var car1 = new car();
car1.height = 5;
car1.weight = 500;
console.log(car1);

Therefore, this gives the proper result.

In Class expressions

They are much like their function counterparts. Therefore, this means no hoisting of class expression.

Therefore, below is an example with the un-named or anonymous variant of the class expression:

var rect = new shapes();
rect.height = 10;
rect.width = 20;
console.log(rect); // Output: TypeError: shapes is not a constructor

var shapes = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

Thus, the correct way to do it is like this:

var shapes = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

var rect = new shapes();
rect.height = 10;
rect.width = 20;
console.log(rect);

Summary

To many developers, Hoisting is an unknown behavior of JavaScript. Many developers overlook it’s importance as well. Moreover, if a developer doesn’t understand hoisting, programs may contain bugs (errors). In order to avoid bugs, always declare all variables at the beginning of every scope. Thus, this is how JavaScript interprets the code, it is always a good rule.

Learn More


Top comments (0)