JavaScript Scope & Hoisting Explained: Complete Guide
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.
// 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:
- Global Scope: Identifiers declared outside of all functions and blocks. Accessible everywhere in the application.
- Function Scope: Identifiers declared with
var,let, orconstinside a function body. Accessible only within that function. - Block Scope: Identifiers declared with
letorconstinside 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 toundefined. Accessing before assignment yieldsundefined.letandconst: 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 immediateReferenceError.
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.