SKU // 57

JavaScript Hoisting

Before JavaScript runs any code in a scope, it first scans for declarations and sets them up. This is called hoisting: it behaves as if declarations were lifted to the top of their scope. What you can do with a name before its line depends on how it was declared.

// Function Declarations: Fully Hoisted

A function declaration is ready to use from the very first line of its scope:

console.log(square(6));   // 36

function square(n) {
  return n * n;
}
36

// var: Hoisted, but Empty

A var name exists from the start, but its value is not assigned until its line runs. Before that, it is undefined:

console.log(level);   // undefined  (no error!)
var level = 5;
console.log(level);   // 5
undefined 5

JavaScript treats that code as if it were written like this:

var level;            // declaration hoisted
console.log(level);   // undefined
level = 5;            // assignment stays where it was
console.log(level);   // 5
Watch out
Silently getting undefined is worse than an error. The program keeps running with a wrong value, and the bug shows up somewhere else later.

Only the declaration is hoisted, not the value

JavaScript hoists the declaration (var y), never the initialization (= 7). Compare these two:

var x = 5;
var y = 7;
console.log(x + " " + y);      // both set first
5 7
var x = 5;
console.log(x + " " + y);      // y used before its line
var y = 7;
5 undefined

In the second version, y exists (its declaration was hoisted), but its value 7 has not been assigned yet. That is why the rule is: declare your variables at the top of every scope. That is how JavaScript reads your code anyway.

// let and const: The Temporal Dead Zone

let and const are hoisted too, but they are locked until their line runs. Touching them early throws an error. The stretch between the start of the scope and the declaration line is called the temporal dead zone:

console.log(score);   // ReferenceError: Cannot access 'score' before initialization
let score = 10;
ReferenceError: Cannot access 'score' before initialization
Note
Read the message closely. It says "cannot access before initialization," not "is not defined." JavaScript knows the name exists; it refuses to let you use it yet. That error is a feature: it catches the mistake immediately.
Note: const with no value
const has one extra rule: it must be given a value on the line it is declared. const carName; on its own is a SyntaxError: Missing initializer in const declaration, and because it is a SyntaxError, none of the script runs. (Some tutorials, including W3Schools, blame that error on using the const too early; the real cause is the missing = value.)

// Function Expressions Follow Variable Rules

A function stored in a variable is only as hoisted as the variable holding it:

greetA();   // TypeError: greetA is not a function   (var holds undefined)
var greetA = function() { return "hi"; };

greetB();   // ReferenceError: Cannot access 'greetB' before initialization
const greetB = () => "hi";
TypeError: greetA is not a function ReferenceError: Cannot access 'greetB' before initialization

// Summary Table

Declaration Used before its line
function name() {}Works
varundefined (silent)
let / constReferenceError
var fn = function...TypeError when called
const fn = () => ...ReferenceError
class Name {}ReferenceError

// Hoisting Happens Per Scope

Declarations are hoisted to the top of their own scope, not the whole file. This can create surprising shadowing:

let theme = "dark";

function showTheme() {
  console.log(theme);   // ReferenceError, not "dark"!
  let theme = "light";
}

showTheme();
ReferenceError: Cannot access 'theme' before initialization

The inner let theme is hoisted to the top of showTheme, so it shadows the outer one for the whole function, including the line before it. And that inner one is still in its dead zone.

// The Practical Rule

Rule of Thumb
Declare variables at the top of their scope, before you use them. Use const and let so any mistake throws an error instead of hiding. Then hoisting almost never matters, apart from the handy ability to call function declarations early.

// Quick Check

What does this log?

console.log(total);
var total = 50;
Show answer
undefined. The declaration var total is hoisted, but the value 50 is not assigned until its own line.

What happens?

console.log(half(10));
const half = n => n / 2;
Show answer
ReferenceError: Cannot access 'half' before initialization. An arrow function stored in const follows const rules: it is in the temporal dead zone until its line runs.

Which one can safely be used on a line above its declaration?

  1. let x = 1;
  2. const f = () => 1;
  3. function f() { return 1; }
  4. class C {}
Show answer
C. Function declarations are fully hoisted, body and all. The others throw a ReferenceError when used early.

// Try It

  1. Click Open Playground and run it. Then change var to let and compare the two results
  2. Call a function declaration on the first line, above the function
  3. Do the same with an arrow function stored in const and read the error
  4. Open the showTheme example with its Try it Yourself button and explain in your notes why it fails
// Video Walkthroughs
Last updated: Oct 10, 2026, 12:53 AM ET