What is the Module pattern and how does it help with encapsulation?
TL;DR
The classic Module pattern uses an IIFE and closure to expose a small public object while keeping other bindings private. It was especially useful before standardized modules. For new code, ES modules are usually the clearer default: each file has module scope and explicitly imports and exports dependencies. Closures and private class fields remain useful when you need per-instance private state rather than one module-scoped value.
var myModule = (function () {var privateVar = 'I am private';function privateMethod() {console.log(privateVar);}return {publicMethod: function () {privateMethod();},};})();myModule.publicMethod(); // Logs: I am private
What is the Module pattern and how does it help with encapsulation?
Introduction to the Module pattern
The Module pattern is a design pattern used in JavaScript to create modules of code that are self-contained. It uses closures to create private and public members, allowing for better organization and encapsulation of code.
How the Module pattern works
The Module pattern typically involves an immediately-invoked function expression (IIFE) that returns an object. This object contains methods and properties that are exposed as the public API of the module. Inside the IIFE, you can define private variables and functions that are not accessible from outside the module.
Example of the Module pattern
Here is a simple example of the Module pattern:
var myModule = (function () {// Private membersvar privateVar = 'I am private';function privateMethod() {console.log(privateVar);}// Public membersreturn {publicMethod: function () {privateMethod();},};})();myModule.publicMethod(); // Logs: I am private
In this example:
privateVarandprivateMethodare private members and cannot be accessed directly from outside the module.publicMethodis a public member and can be accessed from outside the module. It can interact with the private members.
Benefits of using the Module pattern
Encapsulation
The Module pattern helps in encapsulating code by hiding the internal implementation details and exposing only the necessary parts. This makes the code more modular and easier to maintain.
Avoiding global namespace pollution
By using the Module pattern, you can avoid polluting the global namespace with variables and functions. This reduces the risk of naming collisions and makes the code more robust.
Separation of concerns
The Module pattern promotes a clean separation of concerns by allowing you to group related functionality together. This makes the code more organized and easier to understand.
Conclusion
The IIFE Module pattern remains relevant in legacy scripts and embedded code that cannot use a module loader. In modern applications, prefer ES modules for file boundaries and dependency analysis:
// counter.jslet count = 0;export function increment() {count += 1;}export function getCount() {return count;}
count is not exported, but it is shared by every importer of that module instance. If each caller needs independent state, export a factory instead. Also avoid treating closure privacy as a security boundary: code with control of the same page or process may still observe inputs, outputs, and surrounding platform state.
Further reading
- JavaScript Module Pattern: In-Depth
- MDN Web Docs: Closures
- Addy Osmani's Learning JavaScript Design Patterns