Scope & Closures
Scope defines the region of code where a variable is accessible. Closure is when an inner function 'remembers' variables from its outer function even after the outer function has finished running.
Scope prevents naming conflicts between variables. Closures enable powerful patterns like data privacy, factory functions, and React hooks under the hood.
Scope applies everywhere you write code. Closures are used in event handlers, setTimeout callbacks, React's useState and useEffect, and any function returned from another function.
JavaScript uses lexical scoping — scope is determined by where you WRITE the code, not where it runs. Inner functions can always access outer variables, but not vice versa.
📚Key Terms
Lexical Scope— Scope determined by code structure at write-time, not at runtime
Closure— A function that retains access to its outer scope even after the outer function returns
Scope Chain— JavaScript looks for variables starting at local scope, then moves up to parent scopes until global
Code Examples
#1The 3 types of scope
// 1. GLOBAL SCOPE — accessible everywhereconst globalVar = "I'm everywhere";function example() {console.log(globalVar); // ✅ works}// 2. FUNCTION SCOPE — only inside the functionfunction myFunction() {var functionScoped = "only in here";console.log(functionScoped); // ✅ works}// console.log(functionScoped); // ❌ ReferenceError// 3. BLOCK SCOPE — only inside {}{const blockScoped = "only in this block";let alsoBlock = "me too";console.log(blockScoped); // ✅ works}// console.log(blockScoped); // ❌ ReferenceError
#2Closures — function remembers its birthplace
// Inner function remembers outer function's variablesfunction createCounter() {let count = 0; // this variable is "closed over"return function() {count++; // accesses count even after createCounter() finished!return count;};}const counter = createCounter(); // createCounter() has returnedconsole.log(counter()); // 1console.log(counter()); // 2 — count is remembered!console.log(counter()); // 3// Real-world: React useState uses closures internally// Each component instance has its own closed-over state// Practical closure examplefunction makeMultiplier(multiplier) {return (number) => number * multiplier; // closes over multiplier}const double = makeMultiplier(2);const triple = makeMultiplier(3);console.log(double(5)); // 10console.log(triple(5)); // 15
Practice This Concept
Open the playground, paste any example, and experiment. The best way to learn is by breaking things.
Open in Playground