Hoisting in JavaScript

JavaScript has a few quirks that often surprise developers, especially those just getting started. One of the most important concepts to understand is hoisting. If you’ve ever wondered why you can call some functions before they’re defined, or why variables sometimes behave unexpectedly, hoisting is the answer.

In this post, we’ll break down what hoisting is, how it works, and common pitfalls you should avoid.

What Is Hoisting?

Hoisting is JavaScript’s default behavior of moving variable and function declarations to the top of their scope (either the global scope or the current function scope) during the compilation phase.

This doesn’t mean the code itself is physically rearranged. Instead, JavaScript’s engine sets aside memory for variable and function declarations before executing the code.

Function Hoisting

Functions declared using the function keyword are fully hoisted. That means you can call them before their definition appears in the code. Personally, I prefer this style because it allows you to write the meat of your JavaScript module — the main bits, up top and leave the function declarations towards the bottom of the page. This way another developer looking at a module can figure out the gist of what your code is doing and only dig into function definitions as necessary.

sayHello(); // ✅ Works!

function sayHello() {
  console.log("Hello, world!");
}

Why does this work? Because the entire function declaration (name + body) is hoisted to the top of the scope.

Variable Hoisting with var

Variables declared with var are also hoisted, but there’s a catch: only the declaration is hoisted, not the initialization.

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

Here’s what JavaScript actually “sees”:

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

This can lead to confusing bugs if you assume a doesn’t exist at all before the declaration.

Hoisting with let and const

let and const were introduced in ES6 to fix some of the weird behavior of var.
• They are also hoisted, but they go into a “temporal dead zone” (TDZ) from the start of the block until their declaration is encountered.
• This means you cannot access them before they are declared, otherwise you’ll get a runtime error.

console.log(b); // ❌ ReferenceError
let b = 20;

console.log(c); // ❌ ReferenceError
const c = 30;

Hoisting with Function Expressions and Arrow Functions

If you assign a function to a variable (using var, let, or const), only the variable is hoisted, not the function definition.

sayHi(); // ❌ TypeError: sayHi is not a function

var sayHi = function() {
  console.log("Hi!");
};

With var, the variable is hoisted but initialized to undefined, so calling it like a function fails.
With let or const, you’ll hit the temporal dead zone.

Common Pitfalls of Hoisting

Using variables before declaration

console.log(count); // undefined
var count = 5;

Assuming function expressions behave like function declarations

greet(); // ❌ Error
const greet = () => console.log("Hello");

Forgetting about block scope with let and const

{
  console.log(x); // ❌ ReferenceError
  let x = 100;
}

Best Practices to Avoid Hoisting Confusion

  • Always declare variables at the top of their scope.
  • Prefer let and const over var to avoid unexpected undefined values.
  • If you like to put functions towards the end of the file (like I do), make sure that they are defined using the function keyword and not using the arrow syntax.
  • Be mindful of the temporal dead zone with let and const.

Conclusion

Hoisting is one of those JavaScript features that can feel odd at first, but once you understand it, you’ll write cleaner, less error-prone code.

To recap:
• Function declarations are fully hoisted.
• var declarations are hoisted but initialized to undefined.
• let and const are hoisted but live in the temporal dead zone.
• Function expressions and arrow functions behave like variables, not like function declarations.

By keeping these rules in mind, you’ll avoid many headaches and write code that behaves exactly the way you expect.

Leave a Comment

Your email address will not be published. Required fields are marked *