Hello! Welcome back.
In our last lesson, we established the fundamental mechanics of closures: how a function retains a live reference to its lexical environment, allowing it to "remember" variables from the scope where it was created.
Today, we shift our focus from the "what" to the "why." We'll explore the powerful design patterns that closures enable. Specifically, we will describe practical use cases for closures, such as creating private data and function factories. Understanding these patterns is crucial, as they form the foundation for many established practices in JavaScript, including data encapsulation and module systems you've likely encountered in your development career.
Use Case 1: Function Factories
A function factory is a function that returns a new function or an object with methods. The key is that the returned items are configured by the arguments passed to the factory. Closures are what make this pattern stateful and powerful, as the returned function(s) "remember" the configuration from their creation context.
Let's start with a simple, classic example. Imagine you need several functions that add a specific number to their input. Instead of writing add5(x), add10(x), etc., you can create a factory.
Factory Functions and the Module Pattern
The Odin Project article 'Factory Functions and the Module Pattern' provides a clear, initial example of a function factory. It demonstrates how a factory can produce new functions, each with its own closed-over environment.
Please read the section titled 'Closures arenโt scary'. Focus on the makeAddingFunction example. Notice how each call to the factory creates a new function (add5, add8) that maintains its own independent firstNumber variable via a closure.
This pattern becomes even more useful when you return an object containing multiple methods that all share the same closed-over state.
JavaScript Closures Tutorial (Explained in depth)
The following video segment from ColorCode refactors a simple example to demonstrate how a factory can produce an object with multiple methods. This is a common pattern for creating components or modules.
Watch from 04:34 to 09:04. Pay attention to how the human function is transformed from one that immediately executes its inner functions to one that returns an object ({ sayHi, sayHowYouFeel }). The returned methods both share a closure over the name parameter.
Practical Application: Dynamic Event Handlers
A very common real-world use case for function factories is creating event handlers. Let's say you want to assign click handlers to several buttons, but each handler needs to behave slightly differently based on a parameter. A naive approach might fail because you would be invoking the function instead of passing a reference to it. A function factory elegantly solves this.
JavaScript Closures Tutorial (Explained in depth)
This next segment from the same video provides an excellent, practical example of using a factory to generate event handlers for changing font sizes. It clearly illustrates the problem and how closures provide the solution.
Watch from 11:20 to 17:08. The key insight here is understanding why onlick = clickHandler(12) doesn't work as intended, and how rewriting clickHandler as a factory that returns a function solves the problem. The returned function closes over the size parameter, preserving it for when the click event actually occurs.
Use Case 2: Private State and the Module Pattern
One of the most significant applications of closures is emulating private members, a concept familiar from class-based languages. Before the introduction of private class fields (#) in modern JavaScript, closures were the primary way to achieve encapsulation and information hiding.
The principle is simple:
- Define variables within an outer function. These variables are "private" as they are confined to that function's scope.
- Return an object containing methods from the outer function.
- These methods, being closures, have access to the "private" variables, while code outside the function does not.
This creates a public API to interact with a private, internal state.
The simplest illustration of this is the counter.
JavaScript closures and scope โ a practical deep dive
The article 'JavaScript closures and scope โ a practical deep dive' presents the classic makeCounter example. This is the canonical demonstration of a closure being used to maintain private state.
Read the section 'Building intuition: The counter pattern'. Note how counter1 and counter2 each get their own private count variable. The count variable itself is completely inaccessible from the global scope.
The diagram below visualizes what is happening. Each call to the factory creates a new scope object. The returned methods (increment, get) maintain a reference to this scope, keeping it alive.

Let's look at a more realistic example that's closer to what you'd build in an application.
Factory Functions and the Module Pattern
This section from The Odin Project builds on the factory function concept to explicitly introduce private variables. The createUser example is excellent for this.
Read the section titled 'Private variables and functions'. In the createUser example, observe how the reputation variable and the giveReputation function work together. The reputation variable is truly private; it can only be read via getReputation and modified via giveReputation.
The Module Pattern
When you combine a factory function with an IIFE (Immediately Invoked Function Expression), you get the Module Pattern. This is used to create a single, stateful object (a singleton) with private data. This was a dominant pattern for organizing code into self-contained modules before ES6 modules became standard.
JavaScript closures and scope โ a practical deep dive
The 'practical deep dive' article provides a great example of the Module Pattern using an IIFE to create a BankAccount object. This shows how to encapsulate both private state (balance) and private helper functions (validateAmount).
Read 'The module pattern: Private state without classes'. The key is that the IIFE runs once, creates a single scope, and returns a single object whose methods all close over that scope. This effectively creates a singleton with a public API and private implementation details.
Use Case 3: Performance Optimization with Memoization
Memoization is a specific form of caching used to speed up expensive function calls. A higher-order function can wrap an expensive function, storing the results of previous calls. When the function is called again with the same arguments, the cached result is returned instantly.
Closures are essential here to maintain the cache object across multiple calls to the memoized function.
JavaScript closures and scope โ a practical deep dive
This final reading shows how to implement a generic memoize higher-order function. It's a powerful and practical pattern that you might use to optimize computationally heavy tasks.
Read the section 'Practical pattern: Memoization'. The memoize function returns a new function that closes over a cache. This cache persists across all calls to the new function, allowing it to store and retrieve results.
Conclusion
Today we saw how the theoretical concept of closures translates into powerful and ubiquitous design patterns in JavaScript. You are now equipped to not only use but also recognize these patterns in the wild.
Key Takeaways:
- Function Factories: Use closures to create configured functions or objects, a great alternative to constructors for simple object creation. They are especially useful for generating dynamic event handlers.
- Private Data & Encapsulation: Closures are the classic JavaScript mechanism for emulating private variables, hiding implementation details and exposing a controlled public API.
- The Module Pattern: By wrapping a factory in an IIFE, you can create singletonsโself-contained modules with private state and public methods. This was foundational to JavaScript architecture for years.
- Advanced Patterns: Closures also enable sophisticated functional and performance patterns like memoization and currying by allowing functions to maintain state across calls.
What's Next?
In our previous lesson, we saw that closures are all about lexical scopeโwhere a function is defined in the code determines what variables it has access to.
In our next lesson, we will explore another fundamental but often tricky concept: the this keyword. Unlike closures, the value of this is determined not by where a function is defined, but by how it is invoked. We will break down the rules governing its behavior and how to control it explicitly.