What is a “closure” and why should I care
Introduction
You hear all these words: Closure, Higher-Order Function, Callback, First-Class Functions, Currying, Immutability, Hoisting, Temporal Dead Zone… and sometimes, they create this weird mystery in your mind. Instead of helping, they can actually make things more confusing for no good reason.
These terms might be useful for people coming from other languages, but if JavaScript is your first language, we suggest avoiding the jargon. Focus on understanding what’s really happening under the hood—and only dive into these terms when you naturally face a real-world scenario.
No closure
See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.
When the idMaker
function is executed, a new execution context (or “call object”) is created specifically for that function call. This execution context contains all the information needed for the function to execute, including the local variable id
, which is initialized to 1
.
Once the function completes its execution and returns the value of id
, there are no remaining references to the function’s internal state. As a result, the execution context is destroyed, and the memory previously allocated for id
is freed.
The call object acts as a dedicated container in memory for each function call, storing data such as local variables, function parameters, and temporary execution-related information. You can think of it as a temporary JavaScript object “in the sky,” existing only for the duration of the function’s execution. If nothing references the variables after the function finishes, the call object is discarded, freeing up memory. However, memory is kept alive when an inner function holds a reference to the variables in the outer function. This prevents them from being discarded and makes them available for later use. And understanding THAT is what matters. Calling this behavior a “closure” often oversimplifies it into a vague and unnecessarily mysterious concept. If you understand how memory works, this is just the natural behavior of JavaScript (no spiffy name required).
A most basic example
See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.
When sequencialIdGenerator
is run, it creates a private space in memory for the variable id
, starting at 1
(just like before) (it’s “call object”). Instead of returning a value, it returns a function that remembers this space even after sequencialIdGenerator
has finished running. You can think of it as keeping the door to this memory open (which feels like the opposite of “closure”).
The returned function gives you controlled access to the id
variable. Each time you call it, the function updates and returns the next value of id
. This creates a private sequence generator, where id
is safe and untouchable from the outside.
Each time sequencialIdGenerator
is called, it creates a completely new and independent memory space. This means that idMaker
and otherIdMaker
each have their own private id
and don’t interfere with one another.
The private memory stays alive as long as the returned function exists, ensuring that id
is preserved and protected. This allows the generator to maintain its state while keeping everything else out.
And example exposing methods.
See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.
This example introduces the Revealing Module Pattern, where sequencialIdMachine returns an object with multiple methods. Instead of exposing just one function, it provides structured access to the private id
variable through methods like new
, reset
, and current
.
The new method increments and returns the value of id
, while reset sets it back to 1
. The current method allows you to check the value of id without modifying it. By grouping related methods in an object, this pattern makes it easy to manage private state and add new functionality if needed.
Knowing the basics is enough
Most common web tasks won’t need you to explicitly use closures—frameworks often handle those patterns for you. Don’t stress about memorizing closure tricks; just focus on the basic concept. When you hit a unique situation, like needing private state or reusable utilities, you’ll know where to dig and how to apply them. Closures are tools, not daily essentials, but they’re great to have when the need arises.
Coming back to add 3 or 4 helpful scenarios
State examples
See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.
Also, you can check out how you’d do it with classes and modern “private class fields.”
Cache
See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.
We had to write this a little weird to get the result we wanted.
Throttle or debounce
See the Pen HTML cheatsheet 1 / display types by perpetual.education (@perpetual-education) on CodePen.