Top JS Design Patterns

Ahmed A.
3 min readMar 18, 2021

In JavaScript there are things called Design Patterns, these are reusable solutions for common problems when you write your web applications. They are basically templates that provide a solution for your problems. These design patterns give us optimal code for common problems we face when creating our web applications. They allow developers to write clean, easy to read, and efficient code. Doing these helps with getting rid of unnecessary repetitions and improves your code. Here we will explore the most popular JavaScript design patterns, they fall under three categories…

  • Creation Design Pattern
  • Structural Desing Pattern
  • Behavioral Design Pattern

Constructor Design Pattern

This is a method used to initialize newly created objects when memory is allocated. With JavaScript being mainly an OOP language we will look at object constructors. There are three ways to create new objects in JavaScript.

// This creates a new empty Objectvar newObject = {};// This creates a new empty Objectvar newObject = Object.create(Object.prototype);var newObject = newObject();

To access the properties of a function, you need to initialize the object.

const object = new ConstructorObject();

Whereby the new keyword above tells JavaScript that aconstructorObject should act as a constructor. The only caveat to this design pattern is that is does not support inheritance.

Prototype Pattern

We base the prototype pattern on prototypical inheritance. This is when objects act as prototypes for other objects. We can think of a prototype as a blueprint for each object constructor created. For example…

var myCar= {
name:"Ford",
brake:function(){
console.log("Stop! I am applying brakes");
}
Panic : function (){
console.log ( "wait. how do you stop thuis thing?")
}
}
// use object create method to instansiate a new car
var yourCar= object.create(myCar);
//You can now see that one is a prototype of the other
console.log (yourCar.name);

Module Design Pattern

This pattern is improved from the prototype pattern. Different types of modifiers are set in the module pattern. You can avoid conflicts when creating similar functions or properties. There is also the added flexibility of renaming functions publicly. The bad part is the inability to override the created functions from the outside environment. For example…

function AnimalContainter () {const container = [];function addAnimal (name) {
container.push(name);
}
function getAllAnimals() {
return container;
}
function removeAnimal(name) {
const index = container.indexOf(name);
if(index < 1) {
throw new Error('Animal not found in container');
}
container.splice(index, 1)
}
return {
add: addAnimal,
get: getAllAnimals,
remove: removeAnimal
}
}
const container = AnimalContainter();
container.add('Hen');
container.add('Goat');
container.add('Sheep');
console.log(container.get()) //Array(3) ["Hen", "Goat", "Sheep"]
container.remove('Sheep')
console.log(container.get()); //Array(2) ["Hen", "Goat"]

Singleton Pattern

Sometimes we need only one instance needs to be created, for example, a database connection. Creating an instance can only be done when the connection is closed. The singleton pattern is known as a strict pattern, one problem with this pattern is its daunting experience in testing because of its hidden dependencies objects which are not easily singled out for testing. For example…

function DatabaseConnection () {let databaseInstance = null;// tracks the number of instances created at a certain time
let count = 0;
function init() {
console.log(`Opening database #${count + 1}`);
//now perform operation
}
function createIntance() {
if(databaseInstance == null) {
databaseInstance = init();
}
return databaseInstance;
}
function closeIntance() {
console.log('closing database');
databaseInstance = null;
}
return {
open: createIntance,
close: closeIntance
}
}
const database = DatabseConnection();
database.open(); //Open database #1
database.open(); //Open database #1
database.open(); //Open database #1
database.close(); //close database

Observer Pattern

This pattern is handy when objects communicate with other sets of objects at the same time. With the observer pattern, there is no need to push and pull events across states. Instead, the modules involved only change their current state. For example…

function Observer() {
this.observerContainer = [];
}
Observer.prototype.subscribe = function (element) {
this.observerContainer.push(element);
}
// the following removes an element from the containerObserver.prototype.unsubscribe = function (element) {const elementIndex = this.observerContainer.indexOf(element);
if (elementIndex &gt; -1) {
this.observerContainer.splice(elementIndex, 1);
}
}
/**
* we notify elements added to the container by calling
* each subscribed components added to our container
*/
Observer.prototype.notifyAll = function (element) {
this.observerContainer.forEach(function (observerElement) {
observerElement(element);
});
}

Conclusion

As you can see these design patterns are very useful and in this article we have only scratched the surface. There are many more useful design patterns out there for JavaScript and all the other languages. Just keep practicing and you will find when it is best to use these and even when you use them modify them to fit your apps needs.

--

--