JS CodeLab

JavaScript Scope & Hoisting Explained: Complete Guide

By JS CodeLab Engineering Team•Last updated: October 12, 2026•5 min read

Direct Answer & Key Concept

Scope determines the visibility and accessibility of variables in JavaScript. Hoisting is JavaScript's default compilation behavior of allocating memory for variable and function declarations before executing code.

Runnable Code SnippetRun in Playground
// Demonstrating Block Scope and Hoisting
const globalScore = 100;

function evaluateUser() {
  const localBonus = 25;
  
  if (globalScore >= 100) {
    const blockOnlyMessage = "Perfect Score!";
    console.log(blockOnlyMessage, "Total:", globalScore + localBonus);
  }
  
  // console.log(blockOnlyMessage); // ReferenceError! Block-scoped
}

evaluateUser(); // "Perfect Score! Total: 125"

What is Scope in JavaScript?

Scope determines where variables, functions, and objects are accessible during runtime execution. JavaScript enforces three primary layers of scope:

  1. Global Scope: Identifiers declared outside of all functions and blocks. Accessible everywhere in the application.
  2. Function Scope: Identifiers declared with var, let, or const inside a function body. Accessible only within that function.
  3. Block Scope: Identifiers declared with let or const inside curly braces { ... } (e.g., if, for, while). Inaccessible outside that block.

What is Hoisting in JavaScript?

Hoisting refers to the JavaScript engine's behavior during the compilation phase, where declarations are registered in memory before code execution begins:

1. Function Declarations

Function declarations are hoisted completely with their function body. You can safely invoke them before their definition in the file:

greet("Alex"); // Works! "Hello, Alex"

function greet(name) {
  console.log("Hello, " + name);
}

2. Variable Hoisting: var vs let and const

  • var: Hoisted and initialized to undefined. Accessing before assignment yields undefined.
  • let and const: Hoisted but uninitialized. They remain in the Temporal Dead Zone (TDZ) from the start of the block until the declaration statement is executed. Accessing them throws an immediate ReferenceError.
console.log(legacyVar); // undefined
var legacyVar = "I was hoisted";

// console.log(modernLet); // ReferenceError: Cannot access 'modernLet' before initialization
let modernLet = "I am in the TDZ";

Scope Chain and Lexical Scoping

When the JavaScript engine resolves a variable identifier, it searches the current local execution context. If the identifier is not found, it traverses outward through parent enclosing scopes along the scope chain until it reaches the global scope. If the identifier is never found, a ReferenceError is thrown.

Frequently Asked Questions About JavaScript Scope & Hoisting: Complete

What is the difference between block scope and function scope?

Function scope limits variable accessibility to the function where it is declared (created by var, let, or const). Block scope limits accessibility to the specific enclosing curly braces { } (created only by let and const).

Why does var return undefined when hoisted instead of throwing an error?

During compilation, the JavaScript engine allocates memory for var variables and initializes them to undefined. let and const are also allocated in memory, but remain uninitialized in the Temporal Dead Zone until their declaration line is executed.

Are function expressions hoisted in JavaScript?

No. While the variable identifier (e.g. const myFunc) is hoisted according to variable rules, the function assignment itself occurs at runtime. Invoking a function expression before its assignment results in an error.

Related Runnable JavaScript Examples

Ready to test what you learned?

The best way to solidify your JavaScript skills is by writing and running code. Open our free online compiler and test your scripts with real-time console feedback.

Open JavaScript Compiler