JavaScript Design patterns

Introduction

JavaScript on its own can become very tricky and difficult to manage if not carefully written. Patterns help us write clean, maintainable code with the best practices found over time with coding experience.

What is a Pattern?

Patterns are situation-based templates for solving problems. Patterns are proven solutions and can be easily reused.

Patterns are NOT exact solutions. They provide a solution scheme.

Anti-patterns — It’s simple, what not to do.

Why Patterns in JavaScript?

In JavaScript, since there is no formal support for class, there is a lot of flexibility in creating objects or writing our code. Functions are also objects in JavaScript.

We can write our code using Object-Oriented concepts for better coding but JavaScript doesn’t support it formally. Thus, it becomes even more important to have patterns.

Many of the JavaScript patterns are based on Object-Oriented concepts to enforce the developer to write code in a certain way.

Functions are the best way for creating classes in JavaScript.

Pattern Categorisation

  • Object Creational Patterns

As the name suggests, object creational Patterns are patterns that are basically directed towards ways to create an object in JavaScript.

Objects are the fundamental building blocks of any logic we write so we must do it right and do it right the first time to save time and effort with quality code.

Patterns such as Factory, Prototype, Singleton and Constructor are all Object Creational Patterns.

  • Structural Patterns

Structural patterns help with object composition and typically identify simple ways to realize relationships between different objects.

They help ensure that when one part of a system changes, the entire structure of the system doesn’t need to do the same.

They also assist in recasting parts of the system that don’t fit a particular purpose into those that do.

Patterns such as Adapter, Bridge, Facade, Proxy and Flyweight are Structural Patterns.

  • Behavioural Patterns

Based on the way objects play and work together. Behavioural patterns focus on improving or streamlining the communication between disparate objects in a system.

Some behavioural patterns include Iterator, Mediator, Observer, and Visitor.

NOTE: The above categorisation is just to broadly classify different kinds of design patterns. There is much more to them which we will cover after first getting the base concepts of it. Especially when it comes to JavaScript.

Useful design patterns in Javascript

Here is a list of common/useful patterns and their usage explained that can help in identifying the right pattern for a problem presented.

Factory Pattern

Like a factory producing multiple copies of the same unit or product — thus the name. We have a class with common properties and functions and we create objects from this class.

Follow the example below.

OUTPUT:

  • Here, the factory is “peopleFactory”, the common traits are “name”, “age”, “hobby” and “printPerson”.
  • “person1” and “person2” are the products of the factory “peopleFactory”.

Constructor Pattern

This is more like constructors in C++. Constructors are used to creating specific types of objects — they both prepare the object for use and can also accept parameters, which the constructor uses to set the values of member variables when the object is first created.

Each object is created using the ‘new’ keyword would have its own object created with all the parameters.

Consider the example below.

OUTPUT:

  • Here, the objects are always created using the “new” keyword.
  • Each object created have its own properties as well as the function “printPerson”.
  • When creating less number of objects, this shouldn’t be an issue but if the numbers of objects grow, redundancy is a problem.

The disadvantage here is Redundancy.

Solution: Constructors With Prototypes.

Here we use Prototype for avoiding code redundancy and having the same function to be used by all objects.

Follow the code below.

OUTPUT:

  • If you look from line 8–11, the function has been moved out of “peopleConstructor” and we are using “prototype” for defining the function.
  • This code tweak allows all the objects created using “peopleConstructor” like “person1” and “person2” to share a common method instead of having their own instances.
  • The disadvantage here is that the function has been moved outside of the “peopleConstructor” definition so the code is not exactly encapsulated.

Prototype Pattern

Unlike Constructors With Prototypes, which is using the prototype for just defining the function, Prototype Pattern differs.

Consider the code snippet below.

OUTPUT:

  • At the very beginning, the “peoplePrototype” was created empty.
  • We assign “name”, “age” and “hobby” DEFAULT properties using the “prototype” keyword.
  • Similarly, add the function “printPerson”.
  • Now, while creating the objects, we use the “new” keyword to initialize “peoplePrototype” and with Defaults the assign its properties, line 14–17.
  • Lines 22–24 help in determining if “hobby” is in “person1” and if “person1” has its own property.

Dynamic Prototype Pattern

This is something very similar to what we did in “Constructors With Prototypes”.

The difference is that the function also becomes part of the class definition so the encapsulation becomes intact here.

Check out the code below.

OUTPUT:

  • We can now pass the values as parameters for creating objects.
  • Now, when we create the first object, the function “printPerson” gets created then, next object onwards, all objects share the same instance of the function “printPerson”.

Singleton Pattern

In one line — A class with only a single instance with global access points.

Instead of creating multiple instances from the same class, we have a single instance of the class that has to be managed hence the name, “Singleton”.

Check out the code below.

OUTPUT:

  • If you have noticed, both “singleA” and “singleB” are pointing to the same instance.
  • “init” function initializes the singleton.
  • We access private properties via public functions.

Facade Pattern

Facades are a structural pattern. It provides an interface, which shields clients from complex functionality.

When we put up a facade, we present an outward appearance to the world, which may conceal a very different reality, inspiring the name — the facade pattern.

The facade pattern provides a convenient higher-level interface to a larger body of code, hiding its true underlying complexity.

Think of it as simplifying the API being presented to other developers, something that almost always improves usability.

Let us look at the code below.

First is the external independent functions or classes.

“Bank”, “Credit” and “Background” are using Dynamic Prototype Pattern for all the required functionalities for “Mortgage” approval.

Class for “Bank”.

Class for “Credit”.

Class for “Background”.

“Mortgage” acts as an API, which is an interface that hides complex functionalities. Meanwhile, helps with keeping the code loosely coupled.

And this is what runs the show, simple and clean.

OUTPUT:

  • Technically “applyFor” is our API for “Mortgage”.
  • We have used Dynamic Prototype Pattern for other classes which API will be called.
  • When we call the function “run”, it only knows and calls “Mortgage” and need not know what “Mortgage” does to get the final outcome. Thus, creating a “facade”.

Proxy Pattern

“Proxy” as the name suggests, the calling function calls the proxy to get a job done and this proxy checks/processes and then make the actual call to the real guy.

Likewise, the response returns to the client.

Two things happen here:

  • The client need not know the exact function which is getting called.
  • If there is processing required before or after request/response, it can be done in the proxy.

Consider the code below.

The actual method that returns the response.

A proxy method called by the client.

Helper function to keep the logs.

The client function calls the proxy method.

OUTPUT:

  • Client function “run” calls “GeoProxy” with the parameters that will get passed to “GeoCoder”.
  • “run” calls the function with the same parameters multiple times as well.
  • “GeoProxy” checks if the result-set is already in cache for the request, if not it only then calls “GeoCoder”. This avoids the cost of the calls, especially for server calls

We have covered the 7 most useful Javascript Design Patterns in this article with proper examples. There is a lot more to it than just these. Below is a reference to really good books on this topic.

Thank you!

Front end Experience Developer