JavaScript Design Patterns: Your Secret Weapon
Dheeraj Kumar
Senior Engineer @ LTIMindtree | Full-Stack Developer | Cloud Services | Exploring Generative AI & Prompt Engineering | Data Enthusiast
Introduction
In the world of software development, encountering recurring problems is inevitable. That's where the power of design patterns comes in. Think of them as proven, reusable blueprints for tackling common challenges, leading to more flexible, maintainable, and scalable code.
This week, we're diving into the world of JavaScript Design Patterns. These patterns aren't specific to JavaScript syntax, but rather represent a set of best practices applicable across various programming languages. They offer a structured approach to solving recurring issues, ultimately helping you write cleaner, more organized, and efficient code.
While JavaScript doesn't inherently include design patterns as a language feature, understanding and implementing them is crucial for any serious developer. They provide a framework for building robust and adaptable applications.
Types of Design Patterns
Broadly Design Patterns are divided into three types as shown below:
Now we will cover all design patterns one by one more deeply.
Creational Design Pattern
Creational design patterns are a category of design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. In other words, creational patterns are concerned with the process of object creation.
Use to create new Objects with their own Object scope.
There are several creational design patterns that can be used in JavaScript, including:
Constructor Pattern
The Constructor Pattern is a way to create objects in JavaScript that are similar to classes in other object-oriented programming languages. In this pattern, a constructor function is used to create new objects with a set of predefined properties and methods.
Emulates class-like behavior in JavaScript by using constructor functions.
To create an object using the Constructor Pattern in JavaScript, follow these steps:
Step 1:?Create a constructor function:
The constructor function is like a blueprint for creating objects. It should define the properties and methods that will be available on each new object created using the constructor.
Here’s an example:
function Person(name, age,salary) {
this.name = name;
this.age = age;
this.salary=salary;
this.getSalary= function() {
console.log("Hello, my Salary is " + this.salary);
}
}
In this example, the Person constructor takes three parameters, name, age, and salary, and assigns them as properties of the new object that will be created. It also defines a getSalary method that logs salary to the console.
Step 2:?Create a new object using the constructor
To create a new object using the constructor, simply call it with the new keyword and any required arguments.
For example:
var john = new Person("John", 30,70000);
This creates a new Person object with the name “John”, age 30, and a salary of 70000.
Step 3:?Use the new object
Once we’ve created a new object using the constructor, we can use its properties and methods like we would with any other object.
For example:
console.log(john.name); // Output: "John"
john.getSalary(); // Output: "Hello, my salary is 70000"
Module Pattern
The Module Pattern is a widely used design pattern in JavaScript that provides a way to create encapsulated and reusable code by grouping related functions, objects, and variables into a single module or namespace. This pattern helps to avoid naming collisions and provides a clean and structured way to organize code.
Encapsulates related code into a single namespace, avoiding global scope pollution and improving code maintainability.
To implement the Module Pattern in JavaScript, follow these steps:
Step 1:?Create an anonymous function
The first step is to create an anonymous function that will serve as the module. the module will act as the module’s namespace and encapsulate all of the module’s code:
var myModule = (function() {
})();
Step 2:?Add Private variables and methods
Add private variables and methods to the module using the closure technique:
var myModule = (function() {
var privateVariable = 'Hello World';
function privateMethod() {
console.log(privateVariable);
}
return {
};
})();
In this example, privateVariable and privateMethod are not accessible outside of the module because they are defined within the module’s closure.
Step 3:?Add public methods
Add public methods to the module by returning an object literal that contains the public methods:
var myModule = (function() {
var privateVariable = 'Hello World';
function privateMethod() {
console.log(privateVariable);
}
return {
publicMethod: function() {
privateMethod();
}
};
})();
myModule.publicMethod(); // Output: Hello World
In this example, publicMethod is a public method that calls privateMethod, which is a private method within the module.
领英推荐
Step 4:?Add support for dependencies
Add support for dependencies by passing them in as arguments to the module:
var myModule = (function($) {
var privateVariable = 'Hello World';
function privateMethod() {
console.log(privateVariable);
}
return {
publicMethod: function() {
privateMethod();
}
};
})(jQuery);
myModule.publicMethod(); // Output: Hello World
In this example, jQuery is passed in as an argument to the module and is available within the module as?$.
The module pattern is a powerful way to organize and encapsulate code in JavaScript. By using the module pattern, you can create reusable code that is easy to read, maintain, and extend.
Factory Pattern
The Factory Pattern is a creational design pattern that provides an interface for creating objects but allows subclasses to alter the type of objects that will be created. This pattern is often used when you need to create a large number of similar objects, or when the process of creating an object is complex and involves a lot of boilerplate code.
Provides a flexible way to create objects by encapsulating the creation logic within a factory function.
In JavaScript, the Factory Pattern is typically implemented using a factory function, which is a function that returns an object. The factory function can take arguments and use them to customize the object that it creates.
How to Create Factory Pattern in Javascript?
To Create a Factory Pattern in Javascript we need to follow the following steps:
Step 1:?Creating a Factory Function
To create a factory function, we’ll need to define a function that returns an object.
Here’s an example:
function createCar(make, model, year) {
return {
make: make,
model: model,
year: year,
drive: function() {
console.log(`Driving the ${this.make} ${this.model}...`);
}
};
}
In this example, the createCar function takes three arguments: make, model, and year. It then returns an object that has properties for make, model, and year, as well as a drive method that logs a message to the console.
Step 2:?Implementing the Factory Function
To use the factory function, we’ll need to call it and pass in any arguments that it requires.
Here’s an example:
const car1 = createCar('Honda', 'Civic', 2025);
const car2 = createCar('Toyota', 'Corolla', 2025);
In this example, we’re calling the createCar function twice, passing in different arguments each time. This will create two separate objects, one for a Honda Civic and one for a Toyota Corolla.
Step 3:?Using the Factory Function
Once we’ve created the objects using the factory function, we can use them just like any other object in JavaScript.
Here’s an example:
car1.drive(); // logs "Driving the Honda Civic..."
car2.drive(); // logs "Driving the Toyota Corolla..."
Singleton Pattern
The Singleton Pattern is a design pattern that restricts the instantiation of a class to a single instance and provides a global point of access to that instance. In JavaScript, you can implement the Singleton Pattern using a simple object literal or a constructor function.
Ensures that a class or object has only one instance and provides a global point of access.
Here’s an example of how to create a Singleton using an object literal:
const singleton = {
instance: null,
getInstance: function() {
if (!this.instance) {
this.instance = {
// properties and methods of your singleton object
};
}
return this.instance;
}
};
In this example, we define a?singleton?object that has an?instance?property and a?getInstance?method. The?getInstance?method checks whether the?instance?property is null, and if so, it creates a new instance of the object. If the?instance?property is not null, it simply returns the existing instance.
To use the Singleton, you can call the?getInstance?method:
const mySingleton = singleton.getInstance();
This will either create a new instance of the object or return the existing instance, depending on whether an instance has already been created.
Here’s an example of how to create a Singleton using a constructor function:
function MySingleton() {
if (!MySingleton.instance) {
MySingleton.instance = this;
// properties and methods of your singleton object
}
return MySingleton.instance;
}
In this example, we define a?MySingleton?constructor function that checks whether the?instance?property is null and creates a new instance of the object if it is. We also set the?instance?property to the current object using?this, and return the?instance.
To use the Singleton, you can create a new instance of the?MySingleton?constructor function:
const mySingleton = new MySingleton();
This will either create a new instance of the object or return the existing instance, depending on whether an instance has already been created.
The Singleton Pattern offers several advantages, including easy access to a single instance of an object, and control over the instantiation process. However, it can also have some drawbacks, such as tight coupling between the Singleton object and other parts of your code, and difficulty in unit testing. It’s important to weigh the pros and cons of using the Singleton Pattern in your specific use case and to use it judiciously.
Conclusion
In wrapping up this post, we've taken a closer look at the constructor and module patterns—two powerful techniques in JavaScript that help organize your code and encapsulate functionality. We've also touched on other essential creational design patterns, such as the factory and singleton patterns, that provide robust solutions for object creation and lifecycle management. By incorporating these patterns into your coding toolkit, you're well on your way to crafting more elegant, flexible, and maintainable code.
Stay tuned for my next post, where we'll continue our exploration into the exciting world of creational design patterns. Join me on this journey as we unlock new strategies to elevate our coding practices and build even better software together!