Hoisting in JavaScript - What exactly does this mean?

Hoisting in JavaScript - What exactly does this mean?

The concept of hoisting in JavaScript is simple but you may have been taught wrongly.

Assume you are talking with a friend and they ask you about something that you know nothing about. Your response would be "I do not know about that".

In the same way, during execution, our program needs to know about the variables we refer to or else we might get an error.

Let's consider two simple code snippets to illustrate how JavaScript executes.

SNIPPET 1:

var age = 12; // line 1
console.log(age); // line 2

Code Interpretation:
Line 1: Create a variable called age and give it the value 12.
Line 2: Get the value of age and log it to the console.

Notice that in the code snipped above, var age = 12 is written before console.log(age). JavaScript code executes from top to bottom so it is only reasonable that when line 2 executes - because we have the variable age declared in line 1 before its usage in line 2 - there should be no error because having gone through line 1, the JS engine understands that line 2 is simply requesting to log the value of age which is declared in line 1 to the console.

SNIPPET 2:

console.log(age); //line 1
var age = 12; //line 2

Code Interpretation:
Line 1: Get the value of age and log it to the console.
Line 2: Create a variable called age and give it the value 12.

When we run this program (logically speaking), we would expect to get an error because, at line 1, we are already asking for something the compiler doesn't know about yet because it hasn't gotten to line 2 in its execution, but against our logical reasoning, we will discover that this code will run without an error. This code runs without an error because of the concept of hoisting and how variables created with the var keyword behave.

As our usual practice, let's seek to understand the term "hoisting" by examining the word used to coin it.

The construct of the word tells us that it refers to an action taking place but what is the name of the action?

Hoist!

To hoist means to raise something. Hoisting is the process of doing just that 😉

Hoisting can be loosely described as the process of raising variables to the top of their context before the context execution so that every code using (or referring to) that variable will have access to it irrespective of the line in which the code exists in the context. That is why the code written in SNIPPET 2 above could run. This is not something to celebrate until you have sufficient knowledge of what's going on behind the scene.

In JavaScript, the process of hoisting happens during the creation phase of an execution context.

Do you recall from this article that during the creation phase of an execution context, all variable and function declarations are put in memory and assigned a value of undefined? Let me explain what that "memory" is all about.

The memory that is created during the creation phase of an execution context is called a variable object.

In the Global Execution context, it is the Global and/or Script object. While in the function execution context, it is commonly referred to as Activation Object.

Let's put all this knowledge so far together;
Using SNIPPET 2 as a case study, when our program runs, during the creation phase of the global execution context, a memory is created and then the variable age is attached to it with an initial value of undefined

Remember that in the creation phase of an execution context, all variable and function declarations are taken note of. We can dare to say they are hoisted.

The consequence of this phase is that the program now knows about the variable age. Therefore, when the execution phase begins and at line 1 we attempt to access the value of age, we'll get undefined because at that point in the execution phase of the program, the variable has not been assigned a value yet. It merely just exists in memory with a default value.

After line 2, if we try to access the variable again, we'll now get its actual value.

So conceptually, during the creation phase of an execution context, all variable and function declarations are raised to the top of the context so that they are accessible from any line during the execution phase of that context.

There are several ways to create variables in javascript using the keywords var, let, and const. In the next section of this article, let's examine how these keywords affect the accessibility of the variables they are used to create.

Var, Let and Const

The var, let, and const keywords are used to declare variables in JavaScript.

There are some persons with the idea that variables are only hoisted when created with the var keyword (fair point) but I'd like to state that all keywords support hoisting.

The way I think about it is that the keyword we choose to use when creating variables simply affects how they are accessed in the program.

One major difference between the behaviour of variables created with var and those created with let or const; is that accessing variables created using the let or const keyword can only be done after the actual line where they were declared physically in the code. That is, you cannot access variables created with the let or const keyword before they are declared.

The code in the snippet below will result in an error.

console.log(age); // ReferenceError
let age = 12;

Why do I disagree with the idea that variables created using the let or const keyword isn't hoisted?

This is because, during the creation phase of the context where they exist, they are still put in memory and assigned a value of undefined.

That memory is logically located at the top-most of its context making them accessible by child-contexts and child-scopes.

In the global context, a variable created with the let or const keyword is stored in a type of variable object called Script. Those created with the var keyword are stored in a variable object called Global. While in the function context, all variables are stored in the functions' Activation Object.

NB: Do not get too concerned about the meaning of the term variable or activation object. They are simply conceptual terms to refer to a place in a context where variables created in that context are stored.

According to MDN docs, any of the following behaviours can be regarded as hoisting;

  1. Being able to use a variable's value in its scope before the line where it is declared.

  2. Being able to reference a variable in its scope before the line where it is declared, without throwing a ReferenceError, but the value is always undefined.

  3. The declaration of the variable causes behaviour changes in its scope before the line in which it is declared.

All the above-stated behaviours are obtainable at the creation phase of a context.

Summary

People mostly associate the term hoisting to the var keyword but the truth is that even variables created using the var keyword are not listed in the ECMAScript Specification as hoistable declarations.

Hoisting is just an adopted term to describe what happens during the creation phase of an execution context when variables are put in memory and assigned a default value of undefined.

Variables created with the var keyword can be referenced from any line even before the line where they are defined, but trying to reference variables created using the let or const keyword before the line where they are physically declared in the program will result in a referenceError.

In my next article, I talk about scoping in JavaScript and explain (in detail) the effect of using the var, let or const keyword to create variables in your program. It will help you make more informed decisions on which keyword to use when writing your programs.

If this article was helpful to you in any way, kindly like and share (you can like up to 10 times). I'll be glad to engage your questions in the comment section ❤️