Scope & Closures
What is Scope?
Scope determines where variables are accessible in your code.
Types of Scope
| Scope | Description | Keywords |
|---|---|---|
| Global | Accessible everywhere | var (outside function) |
| Function | Accessible inside the function only | var |
| Block | Accessible inside {} only | let, const |
var a = "global"; // global scope
function example() {
var b = "function"; // function scope
if (true) {
let c = "block"; // block scope
var d = "leaked"; // function scope (var ignores block)
}
console.log(d); // "leaked" — var is NOT block scoped
console.log(c); // ReferenceError — let IS block scoped
}
Scope Chain
When a variable is used, JS looks for it in the current scope first, then moves up the chain:
Inner Scope → Outer Scope → ... → Global Scope
let x = "global";
function outer() {
let y = "outer";
function inner() {
let z = "inner";
console.log(x); // "global" — found via scope chain
console.log(y); // "outer" — found in outer scope
console.log(z); // "inner" — found in current scope
}
inner();
}
Closures
A closure is a function that remembers variables from its outer scope even after the outer function has returned.
function createCounter() {
let count = 0; // private variable
return {
increment: () => ++count,
getCount: () => count,
};
}
const counter = createCounter();
counter.increment();
counter.increment();
console.log(counter.getCount()); // 2
// 'count' is still alive because of closure
Classic Loop Problem
// Problem: var is function-scoped
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 — all reference the same 'i'
// Fix 1: use let (block-scoped)
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 0, 1, 2
// Fix 2: IIFE creates a new scope
for (var i = 0; i < 3; i++) {
((j) => {
setTimeout(() => console.log(j), 100);
})(i);
}
// Output: 0, 1, 2
Practical Uses of Closures
- Data privacy — encapsulate state.
- Function factories — create specialized functions.
- Memoization — cache results.
- Event handlers — maintain state between events.
// Memoization
function memoize(fn) {
const cache = {};
return function (...args) {
const key = JSON.stringify(args);
if (cache[key]) return cache[key];
return (cache[key] = fn(...args));
};
}
Key Takeaways
var= function scope,let/const= block scope.- JS uses a scope chain to resolve variables.
- Closures let inner functions access outer variables even after the outer function returns.
- Closures are the foundation for data privacy and many JS patterns.