Closures in JavaScript
Have you ever wondered what happens to a function's local variables after the function has finished executing? Can inner functions still access them? This is where the powerful concept of closures comes into play in JavaScript.
Goto Scope Chain, Scope and Lexical Environment
Let's start by understanding the foundation: Lexical Scoping.
Consider this simple example:
index.js | |
---|---|
When y()
is executed, it needs the value of a
. JavaScript's lexical scoping rule means y()
first looks in its own local scope. Not finding a
there, it looks up to its lexical parent's scope, which is x()
. It finds a
in x()
's scope and uses its value.
This seems straightforward. But what happens when we return the inner function before executing it?
✨ The Magic of Returning Functions
Let's modify the previous example:
index.js | |
---|---|
Here's the puzzle:
- We execute
x()
, and it returns the entire functiony
. This returned function is stored in the variablez
. - After line 9 (
var z = x();
), the functionx()
has finished executing. Its execution context is gone from the call stack. Normally, we'd expect its local variablea
to be garbage collected. - But then, on line 13 (
z();
), we execute the function that used to bey
. This function still needs to access variablea
. How does it find it ifx()
is gone?
It still prints 7
!
This happens because of closures.
🤔 What is a Closure?
A closure is the combination of a function bundled together with references to its surrounding state (the lexical environment). In simpler terms, a closure gives you access to an outer function’s scope from an inner function, even after the outer function has finished executing.
When y
was returned from x
, it didn't just return the function's code; it returned the function along with a persistent reference to its lexical environment, which included the variable a
. This "package" of the function and its environment is the closure.

Closures Capture References, Not Just Values
Closures don't just capture the value of a variable at the moment the closure is created; they capture a reference to the variable itself. This means if the variable's value changes before the closure is executed, the closure will see the updated value.
Consider this:
index.js | |
---|---|
What will z()
print now?
It prints 100
because the closure associated with y
holds a reference to the variable a
. By the time z()
(which is y
) is executed, the value of a
in its remembered lexical scope is 100
. The variable a
wasn't garbage collected because the closure still held a reference to it.

a
Nested Functions and Chained Closures
Closures work across multiple levels of nested functions. An inner function forms closures over the scope of all its parent functions.
index.js | |
---|---|
When child()
executes, it needs a
, b
, and c
.
- It finds
a
in its own scope. - It finds
b
in its lexical parent's scope (parent
). - It finds
c
in its grandparent's scope (grandParent
).
If child
were returned, it would form a closure containing references to a
, b
, and c
.

parent
(containing b
) and grandParent
(containing c
) scopes
Why Use Closures? (Use Cases)
Closures are fundamental to many patterns and techniques in JavaScript:
- Data Hiding and Encapsulation: Creating private variables and methods (Module Pattern).
- Maintaining State in Asynchronous Operations: Callbacks in
setTimeout
, event listeners, or promises often rely on closures to access variables from their original context. - Function Factories: Creating functions with preset configurations (e.g., currying).
- Memoization: Caching results of expensive function calls.
- Iterators: Implementing custom iteration logic.
- Partial Application & Currying: Creating specialized functions from more general ones.
Potential Downsides
While powerful, closures should be used mindfully:
- Memory Consumption: Since variables within a closure's scope are not garbage collected as long as the closure exists, they can potentially consume significant memory if closures are created excessively or hold large data structures unnecessarily.
- Memory Leaks: If closures are inadvertently kept alive (e.g., circular references, uncleared event listeners), the memory they hold onto will never be released, leading to memory leaks.
Understanding closures is key to mastering JavaScript, enabling you to write more elegant, efficient, and powerful code.