JavaScript Hoisting

Hoisting is JavaScript's behavior of moving declarations to the top of their scope before code runs.

What is hoisting?

Before your code executes, the JavaScript engine scans each scope and registers the declarations it finds. As a result, declarations behave as though they were moved to the top of their scope. This is called hoisting. It explains why you can sometimes reference a function or variable on a line that appears before its declaration in the source. Importantly, only declarations are hoisted, not the values assigned to them.

Function declarations are fully hoisted

A function declared with the function keyword is available throughout its entire scope, including lines above where it is written. This lets you organize helper functions at the bottom of a file and still call them earlier. Function expressions and arrow functions assigned to variables do not get this treatment, because only the variable declaration is hoisted, not the assigned function.

Calling a function before its declaration

<!DOCTYPE html>
<html>
<body>

<h2>Function Hoisting</h2>

<script>
greet(); // "Hello!" - works because the declaration is hoisted

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

// A function expression is NOT callable before assignment:
// sayBye(); // TypeError: sayBye is not a function
var sayBye = function () {
  console.log("Bye!");
};
</script>

</body>
</html>

var declarations and undefined

Variables declared with var are hoisted, but only the declaration, not the initialization. Until the line that assigns a value runs, the variable holds the value undefined. This means referencing a var before its assignment does not throw an error; it simply gives undefined, which can hide bugs.

var is hoisted but starts as undefined

<!DOCTYPE html>
<html>
<body>

<h2>var Hoisting</h2>

<script>
console.log(count); // undefined, not an error
var count = 5;
console.log(count); // 5

// The engine treats the above roughly like:
// var count;
// console.log(count); // undefined
// count = 5;
</script>

</body>
</html>

The temporal dead zone with let and const

Variables declared with let and const are also hoisted to the top of their block, but they are not initialized. From the start of the block until the declaration is reached, the variable sits in what is called the temporal dead zone. Accessing it during this window throws a ReferenceError. This design turns a silent undefined into a clear error, helping you catch mistakes sooner.

The temporal dead zone

<!DOCTYPE html>
<html>
<body>

<h2>Temporal Dead Zone</h2>

<script>
// console.log(total); // ReferenceError: Cannot access 'total' before initialization
let total = 100;
console.log(total); // 100

const rate = 0.2; // must be assigned at declaration
</script>

</body>
</html>
DeclarationHoisted?Before initialization
function greet() {}Yes, fullyCallable
var xYesundefined
let xYesReferenceError (TDZ)
const xYesReferenceError (TDZ)
Note: Do not rely on hoisting to use variables before you declare them. Declare variables at the top of their scope and define functions before you call them so your code reads in a predictable order.