Scope & Closures
Where variables live, and how functions remember their environment.
Scope Types
Where variables are visible and accessible.
🌍 Global Scope
const APP_NAME = "VisualJS"; // accessible everywhere
📦 Function Scope
function greet() {
const message = "Hello"; // only inside greet()
}🧱 Block Scope
if (true) {
let x = 10; // only inside this {}
const y = 20;
}var
Function-scoped
let
Block-scoped
const
Block-scoped
Scope Chain
Inner scopes look outward until they find the variable.
const global = "G";
function outer() {
const outerVar = "O";
function inner() {
const innerVar = "I";
console.log(innerVar); // "I" — found locally
console.log(outerVar); // "O" — found in outer
console.log(global); // "G" — found in global
}
inner();
}
// inner → outer → global (chain lookup)💡 Scope lookup goes outward only. Outer scopes can never access inner variables. Siblings can't access each other.
Closures
A function that remembers its surrounding scope even after it executes.
function createCounter() {
let count = 0; // enclosed variable
return function() {
count++;
return count;
};
}createCounter() defines a variable and returns a function that references it.
// Live closure — count persists between clicks:
count is private — only counter() can access it
Closure Patterns
Real-world uses you'll see everywhere.
1. Private State (Module Pattern)
function createWallet(initial) {
let balance = initial;
return {
deposit: (amount) => balance += amount,
withdraw: (amount) => balance -= amount,
getBalance: () => balance,
};
}
const wallet = createWallet(100);
wallet.deposit(50); // balance = 150
wallet.getBalance(); // 150
// wallet.balance → undefined (private!)2. Function Factory
function multiply(factor) {
return (number) => number * factor;
}
const double = multiply(2);
const triple = multiply(3);
double(5); // 10
triple(5); // 153. Memoization / Caching
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}Common Pitfalls
Watch out for these closure mistakes.
// The classic loop bug:
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// Output: 3, 3, 3 ← all same!var is function-scoped. All callbacks share the SAME 'i' variable, which is 3 by the time they run.
FAQ
Common questions about scope and closures.