Hey DEV community! 👋 Today, we’re unpacking one of the most fundamental features in JavaScript:
✅ What is a Closure?
A closure in JavaScript occurs when an inner function remembers and accesses variables from its outer function’s scope, even after the outer function has finished executing. This happens because functions “close over” their surrounding variables.
Closures allow you to:
-> Keep data private
-> Create powerful factory functions
-> Write flexible, modular code
-> Remember state in callbacks and event handlers
Simple Example of a Closure
function outer() {
const message = "Hello from the outer scope!";
function inner() {
console.log(message); // inner can access outer's message
}
return inner;
}
const myClosure = outer(); // outer() runs and returns inner()
myClosure(); // logs: "Hello from the outer scope!"
✅ What’s happening here?
-> outer() runs and returns the inner() function.
-> Even after outer() finishes, inner() still remembers the message variable from outer()’s scope.
Practical Example: Creating Private Variables
Closures are a great way to encapsulate data and avoid polluting the global scope.
function createCounter() {
let count = 0; // private variable
return {
increment() {
count++;
console.log(`Count is now: ${count}`);
},
decrement() {
count--;
console.log(`Count is now: ${count}`);
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // Count is now: 1
counter.increment(); // Count is now: 2
counter.decrement(); // Count is now: 1
console.log(counter.getCount()); // 1
// 🚫 Direct access to 'count' is impossible — it's private!
✅ What’s going on here?
-> count lives inside createCounter()’s scope.
-> The returned object’s methods form closures over count.
-> You control count only through the exposed methods — great for encapsulation!
⚡Common Uses of Closures
✅ Write callbacks (e.g., event handlers, timers)
✅ Implement data privacy in factories or modules
✅ Create partially applied functions
✅ Build memoization utilities to cache results
Pitfall: Closures in Loops
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // logs 3,3,3
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // logs 0,1,2
}
Using let creates a new binding each loop iteration, avoiding closure issues with var.
📝 Key Takeaways
-> Closures allow functions to remember outer variables after execution.
-> They enable data encapsulation and modular code.
-> Understanding closures helps prevent bugs and improves maintainability.
🎉 Closures unlocked! Practice more and watch your JS skills soar. Keep coding! 🚀
Top comments (3)
this is extremely impressive, especially the bit with private variables. took me ages to understand closures back in the day. you think real privacy with closures is enough for most apps or does it ever fall short
Thank you for your feedback.
Love how you broke down the var vs let loop issue - that tripped me up so many times early on. Anyone else have wild bugs from this?