Hoisting is one of JavaScript’s more confusing concepts for beginners, but once you understand it, it becomes a powerful tool in writing better and more predictable code. In simple terms, hoisting is JavaScript’s default behavior of moving declarations to the top of the current scope (script or function).
What is Hoisting?
In JavaScript, declarations (using var
, let
, const
, and function declarations) are moved to the top of their containing scope during the compile phase — before the code is actually executed. This means you can use certain variables and functions before you declare them in your code, without getting an error (although the result may not be what you expect).
However, only the declarations are hoisted — not the initializations.
Variable Hoisting
Using var
javascriptCopyEditconsole.log(x); // undefined
var x = 10;
console.log(x); // 10
Why does the first console.log
not throw an error? Because JavaScript reads it like this during compilation:
javascriptCopyEditvar x; // declaration hoisted
console.log(x); // undefined
x = 10; // initialization stays in place
console.log(x); // 10
So, var
is hoisted and initialized to undefined
until the actual assignment happens.
Using let
and const
javascriptCopyEditconsole.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 5;
With let
and const
, the variable is also hoisted, but it remains in a “temporal dead zone” (TDZ) from the start of the block until the declaration is encountered. You cannot access it before it’s initialized.
Function Hoisting
Function Declarations
javascriptCopyEditsayHello(); // "Hello!"
function sayHello() {
console.log("Hello!");
}
This works because function declarations are hoisted entirely, including their bodies.
Function Expressions
javascriptCopyEditsayHi(); // TypeError: sayHi is not a function
var sayHi = function() {
console.log("Hi!");
};
Here, sayHi
is hoisted like a variable declared with var
, so JavaScript sees it as:
javascriptCopyEditvar sayHi;
sayHi(); // sayHi is undefined at this point
sayHi = function() {
console.log("Hi!");
};
So, trying to call sayHi()
before assignment results in a TypeError
.
Best Practices for Hoisting
- Always declare variables at the top of their scope to avoid confusion.
- Use
let
andconst
instead ofvar
to avoid unexpected hoisting behavior. - Declare functions before you call them, especially if using function expressions.
- Avoid relying on hoisting in your code — while it works, it can make code harder to read and debug.
Summary
Declaration Type | Hoisted? | Initialized? | Access Before Declaration |
---|---|---|---|
var | Yes | undefined | Allowed, returns undefined |
let / const | Yes | No (TDZ) | ReferenceError |
Function Declaration | Yes | Yes | Allowed |
Function Expression | Yes (var) | No | TypeError |
Final Thought
JavaScript hoisting is like having the declarations “moved up” before your code runs, but it’s only the names that are lifted — not the values. Once you understand how this process works, you’ll find it much easier to debug tricky issues and write cleaner, more predictable code.