Easy Guide to JavaScript Closures

Easy Guide to JavaScript Closures (Closure)
JavaScript Closures are one of the most common topics in interviews and are also heavily used in real-world projects.
In this post, we’ll go step by step through what a closure is → basic examples → practical use cases → caveats → additional learning.
📌 What is a Closure?
A closure is "a combination of a function and the lexical environment in which it was declared."
In other words, a closure means that a function remembers the variables from the scope in which it was defined, and it can still access those variables even after the function has finished execution.
function outerFunction() {
let outerVariable = 'I am outer!'
function innerFunction() {
console.log(outerVariable)
}
return innerFunction
}
const myClosure = outerFunction()
myClosure() // Output: I am outer!In the example above, innerFunction is called after outerFunction has already finished execution, but it still has access to outerVariable.
👉 That’s the beauty of closures!
📌 Common Use Cases of Closures
1. Creating Private Variables (Data Encapsulation)
function createCounter() {
let count = 0
return function () {
count++
console.log(count)
}
}
const increment = createCounter()
increment() // 1
increment() // 2
increment() // 3Since count cannot be accessed directly from outside, the state can be safely managed.
2. Preserving State
function userSession(userId) {
let loginCount = 0
return {
login: function () {
loginCount++
console.log(`${userId} login count: ${loginCount}`)
},
getLoginCount: function () {
return loginCount
},
}
}
const sessionA = userSession('userA')
sessionA.login() // userA login count: 1
sessionA.login() // userA login count: 2
console.log(sessionA.getLoginCount()) // 2👉 Perfect for features like login sessions or limiting API requests.
3. Function Factory
function greeter(name) {
return function () {
console.log(`Hello, ${name}!`)
}
}
const greetJohn = greeter('John')
const greetJane = greeter('Jane')
greetJohn() // Hello, John!
greetJane() // Hello, Jane!👉 Great for creating custom button actions or user-specific messages.
4. Implementing Currying
function multiply(a) {
return function (b) {
return a * b
}
}
const double = multiply(2)
const triple = multiply(3)
console.log(double(5)) // 10
console.log(triple(5)) // 15👉 Useful for creating calculators (e.g., discounts) or unit converters.
📌 Things to Watch Out For When Using Closures
-
Be careful of memory leaks!
If you keep unnecessary variables alive, you might waste memory. -
Possible performance issues
Closures rely on scope chains. Using too many closures in tight loops may reduce performance. -
Harder to debug
Sometimes it’s not obvious where a value was changed.
→ Use Chrome DevTools to inspectClosuresnapshots.
❓ Common Closure Interview Questions
- What is a closure in JavaScript?
- How do you use closures to create private variables?
- How do closures affect memory management?
- What is the difference between closures and scope?
👉 These are very common interview questions. Preparing examples in advance will help a lot!
⚖️ Closures vs Related Concepts
- Scope: Defines the accessibility of variables.
- Lexical Environment: The environment in which the code was written.
- Closure: A function remembering its scope and lexical environment.
- this: Refers to the object at execution time. It’s different from closures.
⚠️ Common Closure Mistakes (Anti-Pattern)
for (var i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
// Output: 3, 3, 3👉 Using var leads to unexpected results due to closures.
✅ Solution: Use let or wrap with an IIFE (Immediately Invoked Function Expression).
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i)
}, 1000)
}
// Output: 0, 1, 2📌 Practical Closure Use Cases
- Managing login sessions
- Remembering state inside event handlers
- Rate limiting API calls
- Preserving state in React/Vue custom hooks
function rateLimiter(limit, interval) {
let calls = 0
let start = Date.now()
return function () {
const now = Date.now()
if (now - start > interval) {
start = now
calls = 0
}
if (calls < limit) {
calls++
console.log('API call allowed!')
return true
} else {
console.log('Request blocked!')
return false
}
}
}
const limitedAPI = rateLimiter(3, 5000)
limitedAPI() // API call allowed!
limitedAPI() // API call allowed!
limitedAPI() // API call allowed!
limitedAPI() // Request blocked!📚 Additional Resources
✅ Conclusion
JavaScript closures are a powerful tool for hiding data, preserving state, creating functions, and optimizing performance.
But if used excessively, they can lead to memory leaks and performance issues, so be careful.
👉 Once you truly understand closures and use them appropriately, your code will become cleaner and more robust! 🎉