Skip to main content

Command Palette

Search for a command to run...

Hoisting In JavaScript

What Actually Happens Behind the Scenes.

Updated
Hoisting In JavaScript

Up until now, you’ve learned how to write JavaScript that stores data, performs operations, makes decisions, and organises logic using functions. But there is something deeper happening behind everything you’ve written so far. Something that explains why certain code works even when it logically shouldn’t. Something that confuses almost every beginner at some point.

That concept is hoisting.


Why This Topic Matters.

Let’s start with something that looks strange.

console.log(a); 
var a = 10;

What do you expect this to print?

Most people would say this should throw an error because we are using a before declaring it. But JavaScript prints:

undefined

Now look at this:

console.log(b); 
let b = 20;

This throws an error.

Same pattern. Different result.

Why?

That is exactly what hoisting explains.

What is Hoisting?

Hoisting is JavaScript’s behaviour of moving declarations to the top of their scope before code execution. But this definition alone is not enough. Because hoisting does not behave the same for everything. Different types of declarations behave differently when hoisted. To understand hoisting properly, you need to understand how JavaScript executes code.


How JavaScript Executes Code (Mental Model).

JavaScript does not run your code line by line in a single pass.

It runs in two phases:

  1. Creation Phase

  2. Execution Phase

Creation Phase

Before executing your code, JavaScript scans the entire file and sets up memory.During this phase:

  • Variables are registered

  • Functions are stored in memory

  • Scope is determined

But no code is executed yet.

Execution Phase

Now JavaScript starts running the code line by line. This is where values are assigned and functions are executed.


Understanding Hoisting with var

console.log(a); 
var a = 10;

During the creation phase:

var a = undefined;

During execution:

console.log(a); // undefined 
a = 10;

So var is:

  • hoisted

  • initialised with undefined


Understanding Hoisting with let and const

console.log(b); 
let b = 20;

During the creation phase:

b is hoisted but not initialised

During execution:

Accessing b before initialization throws an error.

This is where the Temporal Dead Zone comes in.


Temporal Dead Zone (TDZ)

The Temporal Dead Zone is the time between:

When a variable is hoisted and when it is initialized During this time, accessing the variable results in a ReferenceError.

console.log(b); // Error 
let b = 20;

Think of TDZ as a restricted zone.The variable exists, but you cannot access it yet.

Quick Comparison

Keyword Hoisted Initialized Accessible Before Declaration
var Yes Yes (undefined) Yes
let Yes No No (TDZ)
const Yes No No (TDZ)

Hoisting with Functions

Now this is where things get interesting.

Function Declaration

greet();
function greet() {    
    console.log("Hello"); 
}

This works.

Why?

Because function declarations are fully hoisted.

During creation phase:

function greet() { 
    console.log("Hello"); 
}

So you can call it before it appears in the code.

Function Expression

greet();
const greet = function() { 
    console.log("Hello"); 
};

This throws an error.

Because it behaves like a variable.

So:

const greet; // TDZ

greet(); // Error

Why Does JavaScript Behave Like This?

JavaScript was designed to be flexible. But older behavior like var caused many bugs because accessing variables before assignment returned undefined.

To fix this, modern JavaScript introduced:

  • let

  • const

  • Temporal Dead Zone

These prevent accidental usage of variables before initialization.


Common Confusion

1. "Hoisting means moving code to top"

Not exactly.

JavaScript does not physically move code. It just allocates memory before execution.

2. "let and const are not hoisted"

Incorrect.

They are hoisted, but not initialized. That is why TDZ exists.

Hoisting Inside Functions

Hoisting works inside functions as well.

function test() { 
    console.log(a); 
    var a = 10; 
}
test();

Output:

undefined

Because inside the function:

var a = undefined; 

Shadowing and Hoisting

function test(){
    console.log(a);
    var a = 20; 
}
test ();

Output:

undefined

Because the inner a shadows the outer a.


Hoisting with let inside block

let a = 10;
function test(){
    console.log(a);
    let a = 20;
}
test();

This throws an error.

Because a is in TDZ inside the function.


Real Mental Model

Instead of thinking hoisting is confusing, think like this:

  • JavaScript first prepares everything

  • Then it executes

During preparation:

  • var gets default value undefined

  • let and const stay uninitialized

  • functions are fully stored


Real-World Example

function calculate() { 
    console.log(total);
    var total = 100;
    if (true) { 
        let discount = 20; 
        console.log(total - discount); 
    } 
}
calculate();

Output:

undefined

80

Understanding hoisting explains why this works.


Common Mistakes

  • Assuming variables behave the same

  • Using var unintentionally

  • Ignoring TDZ

  • Calling function expressions before definition

Best Practices

  • Prefer let and const over var

  • Declare variables at the top of the scope

  • Avoid relying on hoisting behaviour

  • Write predictable code.


Final Thought

Hoisting is not just a concept. It is a reflection of how JavaScript actually runs your code. If you understand hoisting properly, many confusing behaviours in JavaScript stop being confusing. Instead of guessing what the code will do, you start knowing.

And that is the difference between writing code and understanding it.