This content originally appeared on Bits and Pieces - Medium and was authored by Amit Badala
Mastering JavaScript Design Patterns — Module
The Importance of Following Design Patterns in JavaScript
Have you ever found yourself lost in a sea of JavaScript code, struggling to find where a particular function is defined, or trying to figure out how different parts of the code are related? If so, you’re not alone.
Many developers have been in the same situation, and it can be particularly challenging when dealing with a large codebase or working on a team project.

The Need for Design Patterns
Why exactly do we need design patterns? And what happens if we don’t use them?
Design Patterns provide structure, clarity, and efficiency to our code, helping us to write better, more understandable, and maintainable JavaScript. Below are the advantages of employing design patterns
- Design patterns promote well-structured, flexible, and maintainable code, allowing developers to tackle issues consistently and efficiently.
- By improving code readability, they make it easier for any developer to understand the code, benefiting both current and future development.
- Their use simplifies debugging and testing, ultimately resulting in more efficient and high-quality code.
Imagine you’re working on a team project. If everyone uses their own coding style, the codebase can quickly become a mess, making it difficult for team members to understand and contribute to the code.

However, if everyone follows the same design patterns, the code will be more consistent and easier to work with.
💡 In addition to adopting a common design pattern across the board, teams can also adopt a component-driven development system. And open-source tools such as Bit can help streamline the process by providing a platform for storing your components which can then be reused with a simple command.
Learn more here:
Extracting and Reusing Pre-existing Components using bit add
Overview of JavaScript Design Patterns
In JavaScript, design patterns provide a reusable solution to commonly occurring problems. They can be seen as templates or guides to solving issues in a way that’s proven to be effective. Some commonly used JavaScript design patterns include:
- Module Pattern
- Observer Pattern (or Publish/Subscribe pattern)
- Factory Pattern
- Singleton Pattern
- Prototype Pattern
- Decorator Pattern
Each pattern has its unique use cases and can be highly effective when used in the right context. However, for this discussion, we’ll focus on the Module Pattern.
Module Pattern 💪
The Module Pattern uses closures to create private and public encapsulated variables and methods. This helps to organize and structure the code, prevents naming collisions, and keeps the global namespace clean.
This is how the module pattern is defined
(function() {
// The private variables or functions goes here.
return {
// We return the variables or functions here.
}
})();
Let’s break it down with an example to make it easier to understand.
Things before Module Pattern
Let's consider a simple shopping cart example without using any pattern:
// Without using the module pattern
var items = [];
function addItem(item) {
items.push(item);
console.log(item + " has been added to the cart");
}
function removeItem(item) {
var index = items.indexOf(item);
if (index !== -1) {
items.splice(index, 1);
console.log(item + " has been removed from the cart");
}
}
function getItems() {
return items;
}
// Usage
addItem('Apple'); // Console: "Apple has been added to the cart"
addItem('Banana'); // Console: "Banana has been added to the cart"
console.log(getItems()); // Console: ['Apple', 'Banana']
removeItem('Apple'); // Console: "Apple has been removed from the cart"
console.log(getItems()); // Console: ['Banana']
Here, all the functions and the items the array is globally accessible. This can lead to potential problems:
- Naming Collisions: All of these functions and the items variables are in the global scope, so there's a risk of naming collisions. If any other part of the code or a third-party script defines an addItem, removeItem, getItems function or items variable, it could overwrite our own or cause unexpected behavior.
- No Control Over State: Any part of the code can modify the items array directly, potentially causing bugs. For example, a bug or a malicious script could clear the shopping cart by simply doing items = [].
This is not a good situation, especially since large code bases can have a lot of problems maintaining it.
By using the module pattern, we can avoid all these issues
Updating the code with the Module Pattern
Note: Carefully go through the comments
let shoppingCart = (function () {
// Private
// it's only accessible within the module & cannot be accessed from outside
let items = []; // items is private var (not returned by the module)
// Methods
const addItem = (item) => {
items.push(item);
console.log(item + " has been added to the cart");
}
const removeItem = (item) => {
var index = items.indexOf(item);
if (index !== -1) {
items.splice(index, 1);
console.log(item + " has been removed from the cart");
}
}
const getItems = () => {
return items;
}
// Public API
// Anything that is returned by the module is
// public and can be accessed from outside the module.
return {
addItem: addItem,
removeItem: removeItem,
getItems: getItems
};
})();
// Usage
shoppingCart.addItem('Apple'); // Console: "Apple has been added to the cart"
shoppingCart.addItem('Banana'); // Console: "Banana has been added to the cart"
console.log(shoppingCart.getItems()); // Console: ['Apple', 'Banana']
shoppingCart.removeItem('Apple'); // Console: "Apple has been removed from the cart"
console.log(shoppingCart.getItems()); // Console: ['Banana']
With the module pattern, items is private (it’s only accessible within the module & cannot be accessed from outside) and can only be modified through the addItem and removeItem methods.
The addItem, removeItem, and getItems functions are not global, avoiding potential naming collisions.
This makes the code safer, more robust, and easier to maintain.
💡 As mentioned before, you could now extract this shoppingCart logic into a package and use Bit to reuse the logic across different components and applications. With Bit you can easily version, test, and publish — and then install, import, and use your shoppingCart logic in other parts of your application.
Learn more:
Sharing JavaScript Utility Functions Across Projects
Disadvantages
While the Module Pattern in JavaScript offers several advantages, like any design pattern, it is not without its potential drawbacks. Here are a few points to consider:
- Private Data Accessibility: Private data and methods within a module are not accessible from outside the module. This can lead to difficulties when debugging or testing your code as you cannot directly access these private elements.
- Memory Consumption: Each instance of a module creates its own copy of the methods, which can be more memory-intensive than using prototypes, where methods are shared between instances. This could be a concern in memory-constrained environments or when creating a large number of instances.
- Inflexibility: Modules, once defined, cannot be extended or subclassed like a normal constructor function or class. This can limit flexibility in some scenarios.
These are potential disadvantages, but they may not be problems depending on the specific use case. As always, the key is to understand the trade-offs and use the right tool for the job.
Conclusion
So next time you sit down to write some JavaScript, ask yourself: could I benefit from using a design pattern?
The answer will almost certainly be yes. Though it may not necessarily be a Module Pattern.
Build Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:
→ Micro-Frontends
→ Design System
→ Code-Sharing and reuse
→ Monorepo
Learn more:
- Creating a Developer Website with Bit components
- How We Build Micro Frontends
- How we Build a Component Design System
- How to reuse React components across your projects
- 5 Ways to Build a React Monorepo
- How to Create a Composable React App with Bit
- How to Reuse and Share React Components in 2023: A Step-by-Step Guide
- 5 Tools for Building React Component Libraries in 2023
Mastering Javascript Design Pattern — Module was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Amit Badala

Amit Badala | Sciencx (2023-05-17T04:10:05+00:00) Mastering Javascript Design Pattern — Module. Retrieved from https://www.scien.cx/2023/05/17/mastering-javascript-design-pattern-module/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.