If you have ever browsed programming forums or attended JavaScript interviews, you have surely heard the keyword "Closure." It is often described as an abstract, tricky concept, but also the key to becoming a professional JavaScript developer.

So, what exactly is a closure? Why is it so important? And how can we not only understand it but also use it proficiently? Let's unveil this mystery together!
1. What is a Closure? An Easy-to-Understand Definition 💡
Forget the complicated academic definitions for a moment. Imagine this:
A function is like a worker. When created, this worker is given a backpack. Inside that backpack are all the "tools" (variables, constants) the worker might need, taken from the place where he was "born." Even if the worker is sent to work somewhere else, he always carries that backpack and can use the tools inside.
A closure is the combination of that function and the backpack (lexical scope) it carries.

Now, let's get a bit more formal:
A closure is the combination of a function and the lexical environment where that function was declared. A closure allows a child function to access and manipulate the variables of its parent function, even after the parent has finished executing.
Still a bit confusing? Don't worry, let's look at the classic example below.
function createCharacter() {
let characterName = 'Luffy' // Variable defined in the parent function
function showName() {
// Child function
console.log(characterName) // Can access the parent's variable
}
return showName // Return the child function
}
// Call createCharacter, which returns the showName function
const callName = createCharacter()
// At this point, createCharacter has finished executing.
// In theory, 'characterName' should be removed from memory.
// BUT...
callName() // Output: "Luffy"
What magic just happened?
When createCharacter is called, it returns the showName function. When showName was created, it "closed over" its environment, including the variable characterName. It carries the "backpack" containing characterName with it. So, even though createCharacter has finished, callName (which is showName) still remembers and can access characterName. That's a closure!
2. Why are Closures Important? The Real Power 🧠
Closures are not just a theoretical puzzle. They are the foundation for many design patterns and powerful features in JavaScript.
🔐 Data Encapsulation - Hiding Data and Creating Private Variables
In many object-oriented languages, you have keywords like private to protect data. JavaScript (historically) did not have this concept officially, and closures are the solution.
Let's look at a counter example:
function createCounter() {
let count = 0 // The 'count' variable is "private"
return {
increment: function () {
count++
console.log(count)
},
decrement: function () {
count--
console.log(count)
},
getValue: function () {
return count
},
}
}
const counter = createCounter()
counter.increment() // Output: 1
counter.increment() // Output: 2
counter.decrement() // Output: 1
// You cannot access 'count' directly from outside
console.log(counter.count) // Output: undefined
Here, the count variable lives inside createCounter. We cannot access or change it from the outside. The only way to interact with count is through the increment, decrement, and getValue methods returned. These methods form a closure, "remembering" and sharing the same count variable. This is data hiding in action.
🏭 Function Factories
Closures let you create pre-configured functions.
function makeGreeter(greeting) {
return function (name) {
console.log(`${greeting}, ${name}!`)
}
}
const sayHello = makeGreeter('Hello')
const sayXinChao = makeGreeter('Xin chào')
sayHello('John') // Output: Hello, John!
sayXinChao('Son') // Output: Xin chào, Son!
The makeGreeter function is a "factory." Each time you call it, you create a new function (sayHello, sayXinChao) that "remembers" a different greeting value.
⏳ Callbacks and Asynchronous Programming
This is one of the most common uses of closures. When you work with setTimeout, event listeners, or Promises, you are using closures all the time, often without realizing it.
function waitAndSay(message, delay) {
setTimeout(function () {
// This callback is a closure
// It "remembers" the 'message' variable from the outer scope
console.log(message)
}, delay)
}
waitAndSay('Wait 3 seconds and I will appear.', 3000)
The callback passed to setTimeout will be executed after 3 seconds. At that point, waitAndSay has long finished running. But thanks to the closure, the callback still "remembers" the value of message when it was created.
3. Common Pitfall: Loops and Closures ⚠️
This is a classic example that often appears in interviews and confuses many developers.
for (var i = 1; i <= 5; i++) {
setTimeout(function () {
console.log(i)
}, i * 1000)
}
Many expect the result to be 1, 2, 3, 4, 5 printed every second. But the actual result is:
6
6
6
6
6
Why?
varis function-scoped: There is only oneivariable shared by all iterations.- Asynchronous: The
forloop runs very quickly and finishes almost immediately. It queues up 5setTimeoutcalls. When the loop ends, the value ofiis6. - Closure: After 1 second, 2 seconds, etc., when the callbacks in
setTimeoutare executed, they access the variablei. Since they all reference the sameivariable, they all see its final value, which is6.
How to fix it?
✅ Use let: This is the modern and simplest way. let is block-scoped, meaning each iteration of the for loop creates a new i variable.
for (let i = 1; i <= 5; i++) {
setTimeout(function () {
// Each callback now has its own closure with its own 'i'
console.log(i)
}, i * 1000)
}
// Result: 1, 2, 3, 4, 5 (as expected)
Conclusion: Closures Are Not "Magic" 🔮
Closures are not something too mysterious. They are a natural consequence of how JavaScript handles variable scope (specifically, Lexical Scoping—scope determined at code writing time, not runtime).
Mastering closures will help you:
- Write cleaner, more modular code.
- Deepen your understanding of core concepts like scope and context.
- Confidently tackle advanced design patterns and modern JavaScript frameworks.
Hopefully, after this article, "Closure" is no longer a scary keyword, but a powerful tool in your JavaScript skillset. Practice, experiment with examples, and you will see its amazing power.
Good luck!
![[Advanced JS] What is an IIFE? Advanced Applications of IIFE in JavaScript](/images/blog/iife-in-javascript.webp)
![[Advanced JS] What is the Event Loop? Discover How JavaScript Works](/images/blog/event-loop-and-how-javascript-works.webp)
![[Advanced JS] Data Structures & Algorithms: Practical Applications with JavaScript](/images/blog/data-structures-and-algorithms-with-javascript.webp)
![[JS Basics] Distinguishing Shallow Copy and Deep Copy in JavaScript](/images/blog/shallow-copy-and-deep-copy-in-javascript.webp)