Introduction
In our last session, we explored how the JavaScript engine uses the scope chain to resolve variables by searching from the local scope outward. This mechanism is not just a detail of execution—it's the foundation for one of JavaScript's most powerful features. Today, we'll answer a crucial question that builds directly on that knowledge: what happens when a nested function is kept alive and executed after its parent function has already finished running?
The answer lies in closures. A closure is a function that "remembers" the lexical environment in which it was created. This allows it to access and manipulate variables from its parent scope long after that scope would have otherwise been destroyed. By the end of this lesson, you will be able to implement closures to create private state and achieve data encapsulation, a fundamental technique for writing secure, modular, and maintainable code.
The Anatomy of a Closure
At its heart, a closure is the combination of a function and the lexical environment within which that function was declared. In the previous lesson, you learned that an inner function has access to the variables of its outer function. A closure is formed when that inner function is returned, passed as an argument, or otherwise made accessible outside of the outer function's execution.
Let's start with a foundational definition and example from the MDN Web Docs.
Closures - JavaScript - MDN Web Docs - Mozilla
This document provides the canonical definition of a closure and illustrates the concept with two clear examples.
Please read the first major section, up to but not including "Practical closures". Start from the makeFunc example. Pay close attention to the explanation of why the name variable is still accessible after makeFunc has returned. The makeAdder example then demonstrates how each call to the outer function creates a new, independent closure.
As the article explains, the displayName function, when returned and assigned to myFunc, carries its lexical environment with it. This "backpack" of variables (name in this case) is kept alive by the JavaScript engine because the displayName function might need it later. The scope chain we discussed previously doesn't just disappear; it is preserved as part of the closure.
To see what this looks like in practice, the browser's developer tools provide a direct view. When you pause execution inside a function that is a closure, the "Scope" panel often explicitly labels the captured variables.

This ability to "remember" a private set of variables is the key to data encapsulation.
Encapsulation with Factory Functions
Now that we understand the mechanism of a closure, let's apply it to a practical software engineering problem: protecting an object's state from unintended external modification. In many programming paradigms, you'd use private class members for this. In JavaScript, closures are the natural way to achieve this.
A factory function is any function which is not a class or constructor that returns a new object. By defining variables inside the factory function but not returning them on the object itself, we can create private state. We then return methods that have access to this private state via a closure.
The Odin Project provides an excellent walkthrough of this pattern.
Factory Functions and the Module Pattern
This article explains how to use factory functions to create objects with private state, leveraging closures for encapsulation.
First, briefly review the section on factory functions to understand the basic pattern. Then, focus on the section on private variables. The createUser example is key: notice how the reputation variable is defined within the factory's scope but is not returned on the final object. Only the getReputation and giveReputation methods, which form a closure over reputation, are exposed.
This pattern is powerful because it enforces a public API for interacting with an object's state. Callers of the josh object cannot write josh.reputation = -100. They are forced to use the giveReputation method, giving the original author of the createUser factory full control over how the state is modified. This is the principle of encapsulation: bundling data with the methods that operate on that data and restricting direct access to the data itself.
The Module Pattern: Encapsulating a Singleton
Factory functions are great for creating multiple, independent objects, each with its own private state. But what if you only need a single instance of an object, like a service or a utility module, that still needs to manage a private internal state? This is where the Module Pattern comes in.
The module pattern uses an Immediately Invoked Function Expression (IIFE) to create a private scope. An IIFE is a function that is defined and executed in the same expression. This creates a one-time-only lexical environment. Just like with a factory, we can define private variables and functions inside the IIFE and return an object that exposes only the public-facing methods.
The following video from Java Brains provides a step-by-step construction of the module pattern, making it very clear why each piece is necessary.
Scopes and Closures In-depth 20 - The Module Pattern
This video walks through the problem of data privacy in JavaScript and builds the module pattern from the ground up to solve it.
Watch the following segments to see the pattern emerge: The Problem: The presenter first demonstrates how standard object properties in JavaScript are public and cannot be hidden, motivating the need for a better solution. The Solution with Closures: This is the core of the video. Pay close attention to how the firstName and lastName variables are moved from the object properties into the function's local scope. The returned methods (getFirstName, etc.) form a closure, retaining access to these now-private variables. Adding Setters: This section reinforces the concept by showing how the same closure allows for controlled modification of the private state.
The technique you just saw is one of the most classic and important patterns in JavaScript. You are creating a single lexical environment that is shared by a group of public functions, while the state variables (firstName, lastName) remain inaccessible from the global scope.
This is often called the Revealing Module Pattern because the return statement at the end acts as a public API, "revealing" a curated set of methods while hiding the rest of the implementation details.

Let's solidify this with a practical coding example. Imagine you need a simple logger that prefixes every message with a count. You don't want the count to be modifiable from the outside.
const createLogger = () => {
let messageCount = 0; // Private state
// Public API returned as an object
return {
log: (message) => {
messageCount++;
console.log(`${messageCount}: ${message}`);
},
// You could also expose a way to read the state without modifying it
getStatus: () => {
console.log(`Logged ${messageCount} messages so far.`);
}
};
};
// The IIFE version for a single, global logger
const logger = (() => {
let messageCount = 0;
return {
log: (message) => {
messageCount++;
console.log(`${messageCount}: ${message}`);
},
getStatus: () => {
console.log(`Logged ${messageCount} messages so far.`);
}
};
})();
// --- Usage ---
logger.log("Application started."); // Output: 1: Application started.
logger.log("User clicked the button."); // Output: 2: User clicked the button.
// Attempting to tamper with the state fails silently or throws an error
// because `messageCount` is not a property on the `logger` object.
logger.messageCount = -99;
logger.getStatus(); // Output: Logged 2 messages so far. (The count is unaffected)
In this code, messageCount is perfectly encapsulated. The only way to change it is by calling the log method, ensuring the integrity of your module.
Conclusion
Today, you've bridged the gap between the mechanics of the scope chain and one of its most powerful applications. By understanding closures, you've unlocked the ability to write more robust and secure JavaScript.
Key Takeaways:
- Closure: A closure is a function that is bundled with references to its surrounding state (its lexical environment). It "remembers" the variables from the scope in which it was created.
- Persistent State: This mechanism allows a function's local variables to persist in memory even after the function has returned, as long as an inner function that references them is still accessible.
- Data Encapsulation: Closures are JavaScript's primary tool for creating private state. By defining variables within a function but not exposing them directly, you can enforce a controlled public API for interacting with that state.
- Patterns for Privacy:
- Factory Functions: Use these to create multiple objects, each with its own independent private state.
- The Module Pattern (with an IIFE): Use this to create a single, shared instance (a singleton) with private state.
In our next lesson, we will continue to explore the versatility of closures by applying them to solve other common programming challenges, including the classic problem of capturing variables inside loops and further refining our use of function factories.