A closure is created when a function remembers and can access variables from its outer (lexical) scope, even after the outer function has finished execution.
In simple terms: a function "closes over" the variables it needs.
A closure is created when a function remembers and accesses variables from its outer (lexical) scope, even after the outer function has finished execution.
Think of a closure as a function with a backpack. The backpack carries all the variables it needs from where it was born.
A closure is created when a function remembers and can access variables from its outer (lexical) scope, even after the outer function has finished execution.
In simple terms: a function "closes over" the variables it needs.
Closures exist to:
Without closures, JavaScript would struggle with:
Key point: Closures store references, not copies.
jsfunction outer() { let x = 10; return function inner() { return x; // closure over x }; } const fn = outer(); fn(); // 10 (outer() already finished!)
jsfunction makeCounter() { let count = 0; return { increment: () => ++count, decrement: () => --count, value: () => count, }; }
Closures are powerful, but:
Especially risky with event listeners, intervals, and global closures.
Closures capture variables, not values.
js// With var — BUG for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } // Output: 3, 3, 3 (shared i ends at 3) // With let — FIXED for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } // Output: 0, 1, 2 (fresh binding per iteration)
letcreates a new binding per iteration,vardoes not.
jsfunction attachHandler() { const bigData = new Array(1_000_000); button.addEventListener('click', () => { console.log('clicked'); // bigData captured but unused! }); }
Even though bigData isn't used, it stays in memory because the closure captures the whole scope.
Fix: Nullify unused references or remove event listeners in cleanup.
Was this helpful?
4 questions to cement what you just learned.