Javascript Tutorial
Javascript Tutorial Introduction to Javascript JavaScript Code Editors & IDE JavaScript Hello World Example Javascript Syntax and Rules syntax_rules javascript_identifiers JavaScript Keywords & Reserved Words javascript_variables JavaScript Const JavaScript let vs var vs const Data Types in JavaScript JavaScript String Template Literals & String interpolation in JavaScript Tagged Templates in JavaScript String to Number in JavaScript Number Data Type in JavaScript NaN in JavaScript JavaScript Number Min & Max & Safe Values JavaScript EPSILON & Floating point precision Infinity in JavaScript JavaScript Bigint BigInt Vs Number in JavaScript Boolean Data Type in JavaScript Undefined in JavaScript Null in JavaScript Null vs Undefined in JavaScript JavaScript Operators Arithmetic Operators in JavaScript Unary plus & minus operators in JavaScript Increment & Decrement Operators in JavaScript Comparison or Relational operators in JavaScript Strict Equality (==) Loose Equality (===) in JavaScript Ternary Conditional Operator in JavaScript Logical Operators in JavaScript Bitwise Operators in JavaScript Assignment Operators in JavaScript Nullish Coalescing Operator in JavaScript Comma Operator in JavaScript Typeof JavaScript Operator Precedence in JavaScript JavaScript if, else & nested if statement Switch Statement in JavaScript While & Do While Loops in JavaScript For Loop in JavaScript Break statement in JavaScript Continue Statement in JavaScript Arrays in JavaScript Array Constructor in Javascript Sparse Array Vs Dense Array in JavaScript How to merge Arrays in JavaScript Array Methods in JavaScript Functions in JavaScript Function Parameters & Arguments in JavaScript JavaScript Default Parameters Pass by Value and Pass by Reference in Javascript Function Expression in Javascript Nested Functions in JavaScript Immediately-invoked Function Expressions (IIFE) JavaScript Callback Functions Arrow Functions in JavaScript Arguments Object In JavaScript Rest Parameters in JavaScript Objects in Javascript Create Objects in JavaScript JavaScript Object Properties Computed Property Names in JavaScript Object Literal in JavaScript Constructor Function & New Operator in JavaScript Delete Operator in JavaScript hasOwnProperty in JavaScript Using Getters and Setters in Javascript DefineProperty in JavaScript JavaScript Property Descriptors Enumerable, Writable & Configurable Object Destructuring in JavaScript Variable Scope in JavaScript Hoisting in JavaScript Lexical Scope & Closures in JavaScript This in JavaScript Global Object, Window & Globalthis in JavaScript Call function in Javascript Prototype In Javascript Prototype Inheritance in JavaScript Instanceof Operator in JavaScript Spread Operator in JavaScript

Hoisting in JavaScript

Hoisting is a JavaScript behavior, where JavaScript creates the variable and functions before executing the script. This allows us to use the function or variable even before we declare them. In this tutorial, let us learn what hoisting is and how it works in JavaScript.

What is Hoisting

Most sites define Hoisting as JavaScript’s behavior where it moves all declarations to the top of the current scope. Although It is what appears to be happening it is not true.

But first, let us understand what is hoisting using an example.

Take a look at the following example, where we try to access a variable before its declaration.

        
console.log(a)      //undefined
var a=1;  

                
        
    

Since JavaScript is an Interpreted language, we expect it to read each line of code and execute it before moving on to the next line. Hence it is natural to assume that the console.log statement will throw an error. Because when JavaScript executes the console.log statement, the variable a does not exist yet.

However, the console.log output will be undefined.

The undefined value indicates JavaScript already created the variable and also assigned undefined value it. It has created it even though it is yet to execute the line where we have actually created it.

Here it appears that JavaScript has moved the declaration of the variable to the top of the current scope as shown in the code below.

        
var a
console.log(a)      //undefined
a=1; 
   

                
        
    

The same goes for functions. The following code work without any error, although we execute the sayHi function even before we declare it.

        

sayHi();   //Hi
 
 function sayHi() {
    console.log('Hi');
 }
   

                
        
    

Here also it appears that JavaScript moves the sayHi function to the top of the current scope before execution as shown below.

        
function sayHi() {
   console.log('Hi');
}
 
sayHi();   //Hi
   

                
        
    

This behavior of JavaScript where it appears to move all declarations to the top of the current scope is Hoisting.

How does it work

JavaScript is an interpreted language. The JavaScript engine is responsible for interpreting each line of code and executing it.

But JavaScript also compiles the code before executing it. In fact, it executes the code in two phases

Compilation Phase: (or Preparation Phase) where JavaScript runs through the code, Parses it, creates execution context, and does a lot of other stuff.

Execution Phase: where the JavaScript interpreter actually runs the code line-by-line.

As part of the compilation phase, JavaScript looks for all declarations and creates the variables and functions in memory. Hoisting is a side effect of such behavior

In the example below, the JavaScript compiler reads the line var a=1 and creates the variable a in the memory. It assigns the value undefined to the created variable.

        
console.log(a)      //undefined
var a=1; 
 

                
        
    

Note that the statement var a=1 actually consists of two statements. One is declaration i.e. var a and the other one is an assignment a=1. The JavaScript compiler only processes the declaration and not the assignment.

Once the Compiler completes its work, the JavaScript engine begins executing the code one line at a time. It first executes the code console.log(a). Since the variable a is already created and initialized with undefined, it prints undefined in the console window.

JavaScript also hoists the variable declared with let & const. Modify the above example and replace the var with let. Now instead of undefined we get Cannot access [variable name] before initialization.

        
console.log(a)      //Uncaught ReferenceError: Cannot access 'a' before initialization
let a=1;
 

                
        
    

That is because, in the case of let (also const), the JavaScript Hoists the variable but does not initialize it with any value

        
let empty = {};

                
        
    

Object with two numeric properties.

        
let point = { x: 0, y: 0 };
 

                
        
    

More complex values

        
let point = { x: 10, y: 20 };
 
let p2 = { x: point.x, y: point.y + 1 };
 

                
        
    

These property names can include space. For example 'main title'. You need to use the string inside a quote

        
let book = {
  "main title": "Head first Javascript",
}
 
 

                
        
    

You can also make use of a hyphen

        
let book = {
  "main-title": "Javascript Tutorial",
}
                
        
    

The property names can also include reserved words like for and let. The rules of the identifier do not apply to property names.

        
let obj = {
  for: "for is reserved keyword",
  let: "let is also reserved keyword"
};
 
                
        
    

The properties can have any value including the objects, functions, etc. The following book object consists of a property author , which is an object.

        
let book = {
  "main title": "Eloquent JavaScript",
   author: {
    firstName: "Marijn",
    lastName: "Haverbeke"
  }
};
 
 
                
        
    

In the following example, getAuthorName is a function

        
let book = {
    "main title": "Eloquent JavaScript",
    author: {
        firstName: "Marijn",
        lastName: "Haverbeke"
    },
    getAuthorName: function () { return this.author.firstName + ' ' + this.author.lastName }
 
};
 
console.log(book.getAuthorName())
 
                
        
    

Variable Life Cycle

In JavaScript variables also go through three stages during the compilation & execution.

Declaration: phase is where JavaScript registers the variable in the scope.

Initialization: phase is where the engine allocates memory to the variable and assigns an initial value of undefined

Assignment: is where JavaScript assigns value to the variable.

Whether these phases happen at compile-time or at execution time depends on how we declared the variable. The following table shows the relationship between the compilation & execution phase with the let, var, const & function declarations

Keyword Declaration Initialization Assignment
var Compilation Compilation Execution
let & const Compilation Execution Execution
function Compilation Compilation Compilation

The summary of the above table is

  • For a var variable declaration and Initialization are hoisted. But not the assignment.
  • For a let & const variable declaration is hoisted. But not initialization and assignment.
  • For a function declaration, initialization, and assignment are hoisted.

Error Messages

The error messages that JavaScript throws when we try to access a variable give us a hint about the variable’s current state.

Before Declaration

The JavaScript hoists the variables declared with let or const but does not initialize them. When we try to access a variable that is not initialized, we get Cannot access [variable name] before initialization error.

        
console.log(a)      //Uncaught ReferenceError: a is not defined
 
                
        
    

Before Initialization

The JavaScript hoists the variables declared with let or const but does not initialize them. When we try to access a variable that is not initialized, we get Cannot access [variable name] before initialization error.

        
console.log(a)      //Uncaught ReferenceError: Cannot access 'a' before initialization
let a=1; 
                
        
    

After Initialization

JavaScript assigns undefined to every variable which we have declared using var but not yet initialized. In the following code, we have declared the variable but have not assigned any value to it. Hence the code outputs the undefined.

  • that we have not declared the JavaScript throws [variable name] is not defined error.
  • declared but not initialized, then we get the error Cannot access [variable name] before initialization
  • declared & Initialized but not yet assigned any value, then we get undefined. JavaScript does not throw any errors here.

Variable Hoisting

We already looked at the following example.

The javascript does the following in the compilation phase

  1. variable a is registered with the scope
  2. created in memory with the initial value of undefined

Then the execution begins

        
console.log(a)      //undefined
var a=1;
 
                
        
    

The compilation phase when using let.

  1. variable a is registered with the scope

Then the execution begins

        
console.log(a)      //Uncaught ReferenceError: Cannot access 'a' before initialization
let a=1; 
                
        
    

During the compilation phase, the engine registers the variable with the scope. During the execution time, it assigns undefined to a when it encounters the declaration statement

        
let a               //a is assigned undefined here during execution
console.log(a)      //Undefined
a=1;   

        
    

Redeclaring the Variable

The code declares the variable a after initializing it with the value 2. Here the declaration var a is hoisted at the compile time. Hence the code does not throw any errors.

        
a = 2;
var a;
console.log(a);    //2  

        
    

But if we use let instead of var, you will get the Cannot access 'a' before initialization error. This is because the statement let a is hoisted but is not initialized. Hence when we access it on the first line, we get the error.

        
a = 2;              //Uncaught ReferenceError: Cannot access 'a' before initialization
let a;
console.log(a);   

        
    

Undeclared variables

The following code throws the a is not defined error. This is because hoisting works only for the declaration made using the var, let & const. The statement a=2 does not declare the variable hence not hoisted.

        
console.log(a);    //Uncaught ReferenceError: a is not defined
a = 2;     
   

        
    

The following code works fine because the statement a=2 creates the global variable at the time of the execution phase.

        
a = 2;      
console.log(a);    //2   
   

        
    

In the strict mode, you can not use undeclared variables. Hence the above code throws an error.

        
"use strict";
 
a = 2;           //a is not defined
console.log(a);       
   

        
    

Nested Scopes

The variables declared inside the scope are not accessible outside of their scope.

The let variables are block-scoped. JavaScript Engine hoists them to the top of the scope in which we have declared them.

The following example let a=3 statement creates a variable a during the compile time, but within the scope of the code block. Since it is declared with let it is not initialized with undefined. Hence we get the error.

        
var a=2;
{
    console.log(a) //Uncaught ReferenceError: Cannot access 'a' before initialization
    let a=3
}
                
        
    

Note that we already have a variable a declared in the global scope. But console.log will not use it as the a declared in the code block overrides it.

If you remove the let declaration, then the console.log will use the a from the global scope.

        
var a=2;
{
    console.log(a) //2
}
                
        
    

But var variable ignore the block scopes. Hence the following code works without error.

        
var a=2;
{
    console.log(a)      //2
    var a=3
    console.log(a)      //3
}
console.log(a)          //3               
        
    

The Functions also create nested scopes. Hence the variable a inside the function is local to the function and hoisted within the function.

        
var a=2;
 
 sayHi= function() {
     console.log(a)      //undefined
     var a=3
     console.log(a)      //3
 }
 sayHi()
  
 console.log(a)          //2             
         
        
    

Here variable a is hoisted by JavaScript, but the assignment never happens because the If condition evaluates to false.

        
console.log(a)      //undifend
if (false) {
    var a =10
}
console.log(a)      //undifend           
         
        
    

Function Hoisting

JavaScript hoists the Function declarations. In the following example, the compilation phase creates the function variable sayHi, initializes it, and assigns it with the function.

        
sayHi();   //Hi
 
 function sayHi() {
    console.log('Hi');
 }
    
        
    

Function assignment

JavaScript engine only hoists the Function declarations and not assignments. In the following example, we assign the function to a sayHi variable using var. Since the sayHi uses var for its declaration, JavaScript creates it with the initial value of undefined.

        
sayHi()     //Uncaught TypeError: sayHi is not a function
var sayHi = function () {
   console.log('Hi');
}  
    
        
    

You can verify that by checking the value of sayHi

        
console.log(sayHi)     //undefined
var sayHi = function () {
   console.log('Hi');
}   
    
        
    

Naturally, a let declaration throws an error.

        
console.log(sayHi)     //Cannot access 'sayHi' before initialization
let sayHi = function () {
   console.log('Hi');
}    
    
        
    

Function Declaration vs Var Declaration

When a function and a variable have the same name, JavaScript ignores the variable declaration at the compiling step. The function always has a higher priority.

In the following example, sayHi variable points to the function even though the next line of code declares a variable of the same name.

        
 sayHi()             //hi
 
 
 function sayHi () {
    console.log('Hi');
 }  
  
 var sayHi="0"   
    
        
    

Note that let does not allow us the redeclare a variable. The above code with let instead of var will throw the error.

Temporal Dead Zone (TDZ)

The Term Temporal Dead Zone refers to the area in the code where the variable that we are trying to access is declared but not yet initialized. This only happens with let & const declarations because the var declarations are always initialized with undefined

In the code below, the area code from the start of the function until the let declaration is Temporal Dead Zone for variable a. Because of Hoisting, the JavaScript engine has created the variable before the execution of the function and has yet to initialize it.

        
sayHi();   
 
function sayHi() {
   //TDZ starts here for variable a
 
   console.log('Hi');
 
   //TDZ ends here
   let a=10;
}
    
        
    

Similarly, a variable in the global scope TDZ starts from the top.

Avoid Hoisting

Hoisting makes it difficult to detect bugs in JavaScript. It makes the code confusing and difficult to read. Hence it is better to avoid it wherever possible. Here are some tips to avoid Hoisting.

  1. Avoid var. Always use let & const
  2. Always declare the variable at the top of the scope
  3. Make use of "use strict"
  4. Use function expressions instead of function declarations

Read More

  1. JavaScript Tutorial
  2. Hoisting in JavaScript
  3. Object Properties
  4. Lexical Scope & Closure