JavaScript Hoisting and Scope
Understanding variable hoisting and scope rules in JavaScript
JavaScript Hoisting and Scope
1. Hoisting
Definition
- Hoisting refers to the process by which variable and function declarations are moved to the top of their scope during the compilation (parsing) phase.
 - In practice, the code does not physically move; instead, the JavaScript engine registers declarations in memory before executing code.
 - This allows variables and functions to be accessed before their declaration appears in the source code.
 
Variable Hoisting
- 
    
Variables declared with
var:- Declarations are hoisted, but initializations are not.
 - Accessing a 
varvariable before initialization yieldsundefined. 
console.log(x); // undefined var x = 10; - 
    
Variables declared with
letandconst:- Also hoisted, but placed in a Temporal Dead Zone (TDZ) until their declaration is executed.
 - Accessing them before initialization throws a ReferenceError.
 
console.log(y); // ReferenceError let y = 20; 
Function Hoisting
- Functions declared with the 
functionkeyword are hoisted with both declaration and initialization. - 
    
They can be called before their definition appears in the code.
greet(); // "Hello" function greet() { console.log("Hello"); } - Internally, function declarations are fully initialized during hoisting, unlike variables which undergo separate declaration and initialization phases.
 
Why TDZ Exists
- ES6 introduced 
letandconstwith TDZ (Temporal Dead Zone) to improve code predictability. - Prevents accidental access of uninitialized variables.
 - Increases safety by avoiding subtle bugs caused by hoisting.
 
Hoisting in the Execution Model
- 
    
JavaScript is an interpreted language, but engines perform a parsing/compilation step before execution:
- Parsing Phase: Builds the AST (Abstract Syntax Tree) and creates the execution context. Declarations are registered in memory.
 - Execution Phase: Code runs line by line. Variable initialization and function calls are executed.
 
 - 
    
Hoisting occurs during the parsing phase, which explains why declarations appear to “move up” in scope.
 
2. Scope
Definition
- Scope is the region of code where a variable or function is accessible.
 - Determines the lifetime and visibility of variables.
 - Accessing a variable outside its scope leads to a ReferenceError.
 
Types of Scope
- 
    
Global Scope
- Variables declared outside any function/block are globally accessible.
 - 
        
Example:
var globalVar = "I am global"; 
 - 
    
Local Scope
- Created inside functions or blocks.
 - Function Scope: Variables declared with 
varare scoped to the function. - Block Scope: Variables declared with 
letandconstare scoped to the nearest{}block. 
 
Lexical (Static) Scope
- JavaScript uses lexical scoping: scope is determined by where the code is written, not by where it is executed.
 - 
    
Nested functions can access variables from their outer functions, but the reverse is not possible.
function outer() { let a = 10; function inner() { console.log(a); // 10 } inner(); } outer(); 
How Variable Resolution Works
- Every function invocation creates a new Execution Context.
 - 
    
Each execution context has a Lexical Environment:
- Environment Record: Stores local variable/function declarations.
 - Outer Reference: Points to the parent scope’s lexical environment.
 
 - 
    
When a variable is referenced:
- The engine checks the current environment record.
 - If not found, it follows the outer reference chain.
 - If still not found, it checks the global environment.
 - If missing, a ReferenceError is thrown.
 
 
3. Hoisting + Scope Together
- Hoisting determines when variables/functions are registered in memory.
 - Scope determines where they are accessible.
 - 
    
Combined behavior:
- Variables with 
varare hoisted to their enclosing function/global scope and initialized withundefined. let/constare hoisted but locked in the TDZ until initialization is reached in code.- Function declarations are hoisted with full initialization, available throughout their scope.
 
 - Variables with 
 - 
    
This explains why:
console.log(a); // undefined (var hoisting) var a = 1; console.log(b); // ReferenceError (TDZ) let b = 2; greet(); // Works (function hoisting) function greet() { console.log("hi"); } 
4. Summary
- Hoisting: Declarations are processed during the parsing phase, before execution.
 - 
    
Variables:
var→ hoisted, initialized toundefined.let/const→ hoisted, but not initialized (TDZ applies).
 - Functions: fully hoisted (declaration + initialization).
 - Scope: Defines the visibility of variables (global, function, block).
 - Lexical Scope: Variable scope is determined by the code’s written structure, not runtime.
 - Execution Context: Each function creates a lexical environment with an environment record and an outer reference.