Hoisting in JavaScript

Hoisting in JavaScript

What's Hoisting?

Hoisting is a phenomenon in JavaScript, in which we can access variables and functions without any error before their initialization. This happens because even before the code starts executing, memory is allocated to variables and functions.

Hoisting is a JavaScript mechanism where variables and function declarations are moved to the top of their scope before code execution. JavaScript only hoists declarations, not initialisation. Let's take an example:

console.log(message);     //output : undefined
var message = 'JavaScript Hoisting';

The output was undefined as the variable got hosted. Whereas here, the output will get printed:

var message = 'JavaScript Hoisting';
console.log(message);    //output : JavaScript Hoisting

Now take a look here:

console.log(message);     //output : Uncaught Reference Error
let message = 'JavaScript Hoisting';

Here, we see a change instead of getting undefined, we got Uncaught Reference Error.

let was introduced in ES6 and doesn't allow the use of undeclared variables, the interpreter explicitly throws out a Reference error.

JavaScript also hoists the function declared using a function expression syntax for the definition, and that’s how it is available to invoke before the execution reaches there.

var vs let

var is function scoped and has been available from the beginning of JavaScript. Variables will get hoisted using this.

let is block-scoped and has been introduced as part of ES6. Variables will get hoisted using this but not initialized.

In JavaScript, all variables defined with the let or const will be hoisted to the top, but will not be initialized. That means the variable cannot be used until it has been declared.

ES6 has introduced new variable types called let and const. These variable gets hoisted but JavaScript puts them into Temporal Dead Zone and makes them unavailable for usage until the execution reaches there. The reason for this behaviour is that JavaScript wants to minimize runtime errors.

Temporal Dead Zone

It is a behaviour in JavaScript that occurs when declaring a variable with the let and const keywords, but not with var. In ES6, accessing a let or const variable before its declaration (within its scope) causes a ReferenceError.

The time span when that happens, between the creation of a variable’s binding and its declaration, is called the temporal dead zone.

Execution Context Phases

JavaScript is a synchronous and single-threaded language where everything happens inside a Global Execution Context. When we run a JS program, an execution context is created, which is further divided into two phases:

  • Memory Allocation Phase (Variable Environment)

  • Code Execution Phase (Thread of Execution)

Memory Allocation Phase

In the first phase, the entire program is skimmed line by line and memory is allocated to functions and variables. In the case of variables, undefined is stored as a placeholder and in the case of functions, the whole code of the function is stored.

Code Execution Phase

In the second phase, the code is actually executed line by line. The undefined keyword is now replaced by actual values of variables. When there is a function invocation, an entirely new execution context is created which has further two components. When the return keyword is encountered, it just returns all the controls to the global execution context where the function was first invoked. After the complete execution of a function, the execution context related to the instance of the function is deleted. Then, the next line is executed.

Call Stack

The creation/deletion of an execution context is controlled by Call Stack in JavaScript, with Global Execution Context being pushed first and the last to be popped out.

So when, variables are accessed before their initialization (second phase), simply undefined is printed. In case, if the variable is deleted later, an Uncaught Reference Error is thrown saying the variable was not defined. There is a huge difference between not defined and undefined.

When functions are accessed before their initialization (second phase), their output is printed as in the first phase their entire code is stored.

For more information, you can refer here.

Did you find this article valuable?

Support Aakanksha Bhende by becoming a sponsor. Any amount is appreciated!