JavaScript Hoisting

Understanding how JavaScript moves declarations

⬆️ What is Hoisting?

Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope during compilation. It's like JavaScript "lifts" declarations up!


// This works because of hoisting!
console.log(myVar); // undefined (not an error!)
var myVar = "Hello World";

// JavaScript sees it like this:
// var myVar;           // Declaration hoisted
// console.log(myVar);  // undefined
// myVar = "Hello World"; // Assignment stays here
                                    

What Gets Hoisted?

📦

var Variables

Hoisted and initialized with undefined

console.log(x); // undefined
var x = 5;
🚫

let & const

Hoisted but not initialized (Temporal Dead Zone)

console.log(y); // Error!
let y = 10;

Function Declarations

Fully hoisted - can be called before declaration

sayHello(); // Works!
function sayHello() {
    console.log("Hello!");
}

Function Expressions

Not hoisted - treated like variables

sayBye(); // Error!
var sayBye = function() {
    console.log("Bye!");
};

🔹 var Hoisting Example

var declarations are hoisted and initialized with undefined:

// What you write:
console.log("Before declaration:", myName); // undefined
var myName = "Alice";
console.log("After declaration:", myName);  // "Alice"

// How JavaScript interprets it:
// var myName;  // Hoisted to top, initialized with undefined
// console.log("Before declaration:", myName); // undefined
// myName = "Alice";  // Assignment happens here
// console.log("After declaration:", myName);  // "Alice"

Output:

Before declaration: undefined

After declaration: Alice

🔹 let and const Hoisting

let and const are hoisted but not initialized (Temporal Dead Zone):

// This will cause an error
console.log(myLet);    // ReferenceError: Cannot access before initialization
console.log(myConst);  // ReferenceError: Cannot access before initialization

let myLet = "I'm let";
const myConst = "I'm const";

console.log(myLet);    // "I'm let"
console.log(myConst);  // "I'm const"

Output:

ReferenceError: Cannot access 'myLet' before initialization

🔹 Function Hoisting

Function declarations are fully hoisted:

// This works! Function is hoisted
console.log(add(5, 3)); // 8

function add(a, b) {
    return a + b;
}

// But function expressions are not fully hoisted
console.log(multiply(4, 2)); // TypeError: multiply is not a function

var multiply = function(a, b) {
    return a * b;
};

console.log(multiply(4, 2)); // 8 (now it works)

Output:

8

TypeError: multiply is not a function

8

🔹 Practical Hoisting Example

Understanding hoisting helps avoid common mistakes:

// Example showing hoisting behavior
function demonstrateHoisting() {
    console.log("1. myVar:", myVar);     // undefined (hoisted)
    console.log("2. myFunc:", myFunc);   // function (hoisted)
    
    // This would cause an error:
    // console.log("3. myLet:", myLet);  // ReferenceError
    
    var myVar = "I'm a var";
    let myLet = "I'm a let";
    
    function myFunc() {
        return "I'm a function declaration";
    }
    
    console.log("4. myVar:", myVar);     // "I'm a var"
    console.log("5. myLet:", myLet);     // "I'm a let"
    console.log("6. myFunc():", myFunc()); // "I'm a function declaration"
}

demonstrateHoisting();

Output:

1. myVar: undefined

2. myFunc: function myFunc() { return "I'm a function declaration"; }

4. myVar: I'm a var

5. myLet: I'm a let

6. myFunc(): I'm a function declaration

🔹 Best Practices

To avoid hoisting confusion:

  • Declare variables at the top of their scope
  • Use let and const instead of var when possible
  • Define functions before using them
  • Use function expressions for conditional function creation
// Good practice
function goodExample() {
    // Declare variables at the top
    let name = "John";
    let age = 25;
    const PI = 3.14159;
    
    // Define functions before using
    function calculateArea(radius) {
        return PI * radius * radius;
    }
    
    // Use them
    console.log(`${name} is ${age} years old`);
    console.log(`Circle area: ${calculateArea(5)}`);
}

🧠 Test Your Knowledge

What happens when you access a 'var' variable before it's declared?