Cover image
Back-end
22 minute read

The Comprehensive Guide to JavaScript Design Patterns

As a good JavaScript developer, you strive to write clean, healthy, and maintainable code. While you solve interesting and unique challenges, you’ve likely found that you’re often writing code that looks similar to the code for an entirely different problem you’ve handled before. You may not know it, but you’ve used a design pattern.

As a good JavaScript developer, you strive to write clean, healthy, and maintainable code. You solve interesting challenges that, while unique, don’t necessarily require unique solutions. You’ve likely found yourself writing code that looks similar to the solution of an entirely different problem you’ve handled before. You may not know it, but you’ve used a JavaScript design pattern. Design patterns are reusable solutions to commonly occurring problems in software design.

The Comprehensive Guide to JavaScript Design Patterns

During any language’s lifespan, many such reusable solutions are made and tested by a large number of developers from that language’s community. It is because of this combined experience of many developers that such solutions are so useful because they help us write code in an optimized way while at the same time solving the problem at hand.

The main benefits we get from design patterns are the following:

  • They are proven solutions: Because design patterns are often used by many developers, you can be certain that they work. And not only that, you can be certain that they were revised multiple times and optimizations were probably implemented.
  • They are easily reusable: Design patterns document a reusable solution which can be modified to solve multiple particular problems, as they are not tied to a specific problem.
  • They are expressive: Design patterns can explain a large solution quite elegantly.
  • They ease communication: When developers are familiar with design patterns, they can more easily communicate with one another about potential solutions to a given problem.
  • They prevent the need for refactoring code: If an application is written with design patterns in mind, it is often the case that you won’t need to refactor the code later on because applying the correct design pattern to a given problem is already an optimal solution.
  • They lower the size of the codebase: Because design patterns are usually elegant and optimal solutions, they usually require less code than other solutions.

I know you’re ready to jump in at this point, but before you learn all about design patterns, let’s review some JavaScript basics.

A Brief History of JavaScript

JavaScript is one of the most popular programming languages for web development today. It was initially made as a sort of a “glue” for various displayed HTML elements, known as a client-side scripting language, for one of the initial web browsers. Called Netscape Navigator, it could only display static HTML at the time. As you might assume, the idea of such a scripting language led to browser wars between the big players in the browser development industry back then, such as Netscape Communications (today Mozilla), Microsoft, and others.

Each of the big players wanted to push through their own implementation of this scripting language, so Netscape made JavaScript (actually, Brendan Eich did), Microsoft made JScript, and so forth. As you can image, the differences between these implementations were great, so development for web browsers was made per-browser, with best-viewed-on stickers that came with a web page. It soon became clear that we needed a standard, a cross-browser solution which would unify the development process and simplify the creation of web pages. What they came up with is called ECMAScript.

ECMAScript is a standardized scripting language specification which all modern browsers try to support, and there are multiple implementations (you could say dialects) of ECMAScript. The most popular one is the topic of this article, JavaScript. Since its initial release, ECMAScript has standardized a lot of important things, and for those more interested in the specifics, there is a detailed list of standardized items for each version of the ECMAScript available on Wikipedia. Browser support for ECMAScript versions 6 (ES6) and higher are still incomplete and have to be transpiled to ES5 in order to be fully supported.

What Is JavaScript?

In order to fully grasp the contents of this article, let’s make an introduction to some very important language characteristics that we need to be aware of before diving into JavaScript design patterns. If someone were to ask you “What is JavaScript?” you might answer somewhere in the lines of:

JavaScript is a lightweight, interpreted, object-oriented programming language with first-class functions most commonly known as a scripting language for web pages.

The aforementioned definition means to say that JavaScript code has a low memory footprint, is easy to implement, and easy to learn, with a syntax similar to popular languages such as C++ and Java. It is a scripting language, which means that its code is interpreted instead of compiled. It has support for procedural, object-oriented, and functional programming styles, which makes it very flexible for developers.

So far, we have taken a look at all of the characteristics which sound like many other languages out there, so let’s take a look at what is specific about JavaScript in regard to other languages. I am going to list a few characteristics and give my best shot at explaining why they deserve special attention.

JavaScript Supports First-class Functions

This characteristic used to be troublesome for me to grasp when I was just starting with JavaScript, as I came from a C/C++ background. JavaScript treats functions as first-class citizens, meaning you can pass functions as parameters to other functions just like you would any other variable.

// we send in the function as an argument to be
// executed from inside the calling function
function performOperation(a, b, cb) {
    var c = a + b;
    cb(c);
}

performOperation(2, 3, function(result) {
    // prints out 5
    console.log("The result of the operation is " + result);
})

JavaScript Is Prototype-based

As is the case with many other object-oriented languages, JavaScript supports objects, and one of the first terms that comes to mind when thinking about objects is classes and inheritance. This is where it gets a little tricky, as the language doesn’t support classes in its plain language form but rather uses something called prototype-based or instance-based inheritance.

It is just now, in ES6, that the formal term class is introduced, which means that the browsers still don’t support this (if you remember, as of writing, the last fully supported ECMAScript version is 5.1). It is important to note, however, that even though the term “class” is introduced into JavaScript, it still utilizes prototype-based inheritance under the hood.

Prototype-based programming is a style of object-oriented programming in which behavior reuse (known as inheritance) is performed via a process of reusing existing objects via delegations that serve as prototypes. We will dive into more detail with this once we get to the design patterns section of the article, as this characteristic is used in a lot of JavaScript design patterns.

JavaScript Event Loops

If you have experience working with JavaScript, you are surely familiar with the term callback function. For those not familiar with the term, a callback function is a function sent as a parameter (remember, JavaScript treats functions as first-class citizens) to another function and gets executed after an event fires. This is usually used for subscribing to events such as a mouse click or a keyboard button press.

Graphic depiction of the JavaScript event loop

Each time an event, which has a listener attached to it, fires (otherwise the event is lost), a message is being sent to a queue of messages which are being processed synchronously, in a FIFO manner (first-in-first-out). This is called the event loop.

Each of the messages on the queue has a function associated with it. Once a message is dequeued, the runtime executes the function completely before processing any other message. This is to say, if a function contains other function calls, they are all performed prior to processing a new message from the queue. This is called run-to-completion.

while (queue.waitForMessage()) {
    queue.processNextMessage();
}

The queue.waitForMessage() synchronously waits for new messages. Each of the messages being processed has its own stack and is processed until the stack is empty. Once it finishes, a new message is processed from the queue, if there is one.

You might have also heard that JavaScript is non-blocking, meaning that when an asynchronous operation is being performed, the program is able to process other things, such as receiving user input, while waiting for the asynchronous operation to complete, not blocking the main execution thread. This is a very useful property of JavaScript and a whole article could be written just on this topic; however, it is outside of the scope of this article.

What Are Design Patterns?

As I said before, design patterns are reusable solutions to commonly occurring problems in software design. Let’s take a look at some of the categories of design patterns.

Proto-patterns

How does one create a pattern? Let’s say you recognized a commonly occurring problem, and you have your own unique solution to this problem, which isn’t globally recognized and documented. You use this solution every time you encounter this problem, and you think that it’s reusable and that the developer community could benefit from it.

Does it immediately become a pattern? Luckily, no. Oftentimes, one may have good code writing practices and simply mistake something that looks like a pattern for one when, in fact, it is not a pattern.

How can you know when what you think you recognize is actually a design pattern?

By getting other developers’ opinions about it, by knowing about the process of creating a pattern itself, and by making yourself well acquainted with existing patterns. There is a phase a pattern has to go through before it becomes a full-fledged pattern, and this is called a proto-pattern.

A proto-pattern is a pattern-to-be if it passes a certain period of testing by various developers and scenarios where the pattern proves to be useful and gives correct results. There is quite a large amount of work and documentation—most of which is outside the scope of this article—to be done in order to make a fully-fledged pattern recognized by the community.

Anti-patterns

As a design pattern represents good practice, an anti-pattern represents bad practice.

An example of an anti-pattern would be modifying the Object class prototype. Almost all objects in JavaScript inherit from Object (remember that JavaScript uses prototype-based inheritance) so imagine a scenario where you altered this prototype. Changes to the Object prototype would be seen in all of the objects that inherit from this prototype—which would be most JavaScript objects. This is a disaster waiting to happen.

Another example, similar to one mentioned above, is modifying objects that you don’t own. An example of this would be overriding a function from an object used in many scenarios throughout the application. If you are working with a large team, imagine the confusion this would cause; you’d quickly run into naming collisions, incompatible implementations, and maintenance nightmares.

Similar to how it is useful to know about all of the good practices and solutions, it is also very important to know about the bad ones too. This way, you can recognize them and avoid making the mistake up front.

Design Pattern Categorization

Design patterns can be categorized in multiple ways, but the most popular one is the following:

  • Creational design patterns
  • Structural design patterns
  • Behavioral design patterns
  • Concurrency design patterns
  • Architectural design patterns

Creational Design Patterns

These patterns deal with object creation mechanisms which optimize object creation compared to a basic approach. The basic form of object creation could result in design problems or in added complexity to the design. Creational design patterns solve this problem by somehow controlling object creation. Some of the popular design patterns in this category are:

  • Factory method
  • Abstract factory
  • Builder
  • Prototype
  • Singleton

Structural Design Patterns

These patterns deal with object relationships. They ensure that if one part of a system changes, the entire system doesn’t need to change along with it. The most popular patterns in this category are:

  • Adapter
  • Bridge
  • Composite
  • Decorator
  • Facade
  • Flyweight
  • Proxy

Behavioral Design Patterns

These types of patterns recognize, implement, and improve communication between disparate objects in a system. They help ensure that disparate parts of a system have synchronized information. Popular examples of these patterns are:

  • Chain of responsibility
  • Command
  • Iterator
  • Mediator
  • Memento
  • Observer
  • State
  • Strategy
  • Visitor

Concurrency Design Patterns

These types of design patterns deal with multi-threaded programming paradigms. Some of the popular ones are:

  • Active object
  • Nuclear reaction
  • Scheduler

Architectural Design Patterns

Design patterns which are used for architectural purposes. Some of the most famous ones are:

  • MVC (Model-View-Controller)
  • MVP (Model-View-Presenter)
  • MVVM (Model-View-ViewModel)

In the following section, we are going to take a closer look at some of the aforementioned design patterns with examples provided for better understanding.

Design Pattern Examples

Each of the design patterns represents a specific type of solution to a specific type of problem. There is no universal set of patterns that is always the best fit. We need to learn when a particular pattern will prove useful and whether it will provide actual value. Once we are familiar with the patterns and scenarios they are best suited for, we can easily determine whether or not a specific pattern is a good fit for a given problem.

Remember, applying the wrong pattern to a given problem could lead to undesirable effects such as unnecessary code complexity, unnecessary overhead on performance, or even the spawning of a new anti-pattern.

These are all important things to consider when thinking about applying a design pattern to our code. We are going to take a look at some of the design patterns I personally found useful and believe every senior JavaScript developer should be familiar with.

Constructor Pattern

When thinking about classical object-oriented languages, a constructor is a special function in a class which initializes an object with some set of default and/or sent-in values.

Common ways to create objects in JavaScript are the three following ways:

// either of the following ways can be used to create a new object
var instance = {};
// or
var instance = Object.create(Object.prototype);
// or
var instance = new Object();

After creating an object, there are four ways (since ES3) to add properties to these objects. They are the following:

// supported since ES3
// the dot notation
instance.key = "A key's value";

// the square brackets notation
instance["key"] = "A key's value";

// supported since ES5
// setting a single property using Object.defineProperty
Object.defineProperty(instance, "key", {
    value: "A key's value",
    writable: true,
    enumerable: true,
    configurable: true
});

// setting multiple properties using Object.defineProperties
Object.defineProperties(instance, {
    "firstKey": {
        value: "First key's value",
        writable: true
    },
    "secondKey": {
        value: "Second key's value",
        writable: false
    }
});

The most popular way to create objects is the curly brackets and, for adding properties, the dot notation or square brackets. Anyone with any experience with JavaScript has used them.

We mentioned earlier that JavaScript doesn’t support native classes, but it does support constructors through the use of a “new” keyword prefixed to a function call. This way, we can use the function as a constructor and initialize its properties the same way we would with a classic language constructor.

// we define a constructor for Person objects
function Person(name, age, isDeveloper) {
    this.name = name;
    this.age = age;
    this.isDeveloper = isDeveloper || false;

    this.writesCode = function() {
      console.log(this.isDeveloper? "This person does write code" : "This person does not write code");
    }
}

// creates a Person instance with properties name: Bob, age: 38, isDeveloper: true and a method writesCode
var person1 = new Person("Bob", 38, true);
// creates a Person instance with properties name: Alice, age: 32, isDeveloper: false and a method writesCode
var person2 = new Person("Alice", 32);

// prints out: This person does write code
person1.writesCode();
// prints out: this person does not write code
person2.writesCode();

However, there is still room for improvement here. If you’ll remember, I mentioned previously that JavaScript uses prototype-based inheritance. The problem with the previous approach is that the method writesCode gets redefined for each of the instances of the Person constructor. We can avoid this by setting the method into the function prototype:

// we define a constructor for Person objects
function Person(name, age, isDeveloper) {
    this.name = name;
    this.age = age;
    this.isDeveloper = isDeveloper || false;
}

// we extend the function's prototype
Person.prototype.writesCode = function() {
    console.log(this.isDeveloper? "This person does write code" : "This person does not write code");
}

// creates a Person instance with properties name: Bob, age: 38, isDeveloper: true and a method writesCode
var person1 = new Person("Bob", 38, true);
// creates a Person instance with properties name: Alice, age: 32, isDeveloper: false and a method writesCode
var person2 = new Person("Alice", 32);

// prints out: This person does write code
person1.writesCode();
// prints out: this person does not write code
person2.writesCode();

Now, both instances of the Person constructor can access a shared instance of the writesCode() method.

Module Pattern

As far as peculiarities go, JavaScript never ceases to amaze. Another peculiar thing to JavaScript (at least as far as object-oriented languages go) is that JavaScript does not support access modifiers. In a classical OOP language, a user defines a class and determines access rights for its members. Since JavaScript in its plain form supports neither classes nor access modifiers, JavaScript developers figured out a way to mimic this behavior when needed.

Before we go into the module pattern specifics, let’s talk about the concept of closure. A closure is a function with access to the parent scope, even after the parent function has closed. They help us mimic the behavior of access modifiers through scoping. Let’s show this via an example:

// we  used an immediately invoked function expression
// to create a private variable, counter
var counterIncrementer = (function() {
    var counter = 0;

    return function() {
        return ++counter;
    };
})();

// prints out 1
console.log(counterIncrementer());
// prints out 2
console.log(counterIncrementer());
// prints out 3
console.log(counterIncrementer());

As you can see, by using the IIFE, we have tied the counter variable to a function which was invoked and closed but can still be accessed by the child function that increments it. Since we cannot access the counter variable from outside of the function expression, we made it private through scoping manipulation.

Using the closures, we can create objects with private and public parts. These are called modules and are very useful whenever we want to hide certain parts of an object and only expose an interface to the user of the module. Let’s show this in an example:

// through the use of a closure we expose an object
// as a public API which manages the private objects array
var collection = (function() {
    // private members
    var objects = [];

    // public members
    return {
        addObject: function(object) {
            objects.push(object);
        },
        removeObject: function(object) {
            var index = objects.indexOf(object);
            if (index >= 0) {
                objects.splice(index, 1);
            }
        },
        getObjects: function() {
            return JSON.parse(JSON.stringify(objects));
        }
    };
})();

collection.addObject("Bob");
collection.addObject("Alice");
collection.addObject("Franck");
// prints ["Bob", "Alice", "Franck"]
console.log(collection.getObjects());
collection.removeObject("Alice");
// prints ["Bob", "Franck"]
console.log(collection.getObjects());

The most useful thing that this pattern introduces is the clear separation of private and public parts of an object, which is a concept very similar to developers coming from a classical object-oriented background.

However, not everything is so perfect. When you wish to change the visibility of a member, you need to modify the code wherever you have used this member because of the different nature of accessing public and private parts. Also, methods added to the object after their creation cannot access the private members of the object.

Revealing Module Pattern

This pattern is an improvement made to the module pattern as illustrated above. The main difference is that we write the entire object logic in the private scope of the module and then simply expose the parts we want to be public by returning an anonymous object. We can also change the naming of private members when mapping private members to their corresponding public members.

// we write the entire object logic as private members and
// expose an anonymous object which maps members we wish to reveal
// to their corresponding public members
var namesCollection = (function() {
    // private members
    var objects = [];

    function addObject(object) {
        objects.push(object);
    }

    function removeObject(object) {
        var index = objects.indexOf(object);
        if (index >= 0) {
            objects.splice(index, 1);
        }
    }

    function getObjects() {
        return JSON.parse(JSON.stringify(objects));
    }

    // public members
    return {
        addName: addObject,
        removeName: removeObject,
        getNames: getObjects
    };
})();

namesCollection.addName("Bob");
namesCollection.addName("Alice");
namesCollection.addName("Franck");
// prints ["Bob", "Alice", "Franck"]
console.log(namesCollection.getNames());
namesCollection.removeName("Alice");
// prints ["Bob", "Franck"]
console.log(namesCollection.getNames());

The revealing module pattern is one of at least three ways in which we can implement a module pattern. The differences between the revealing module pattern and the other variants of the module pattern are primarily in how public members are referenced. As a result, the revealing module pattern is much easier to use and modify; however, it may prove fragile in certain scenarios, like using RMP objects as prototypes in an inheritance chain. The problematic situations are the following:

  1. If we have a private function which is referring to a public function, we cannot override the public function, as the private function will continue to refer to the private implementation of the function, thus introducing a bug into our system.
  2. If we have a public member pointing to a private variable, and try to override the public member from outside the module, the other functions would still refer to the private value of the variable, introducing a bug into our system.

Singleton Pattern

The singleton pattern is used in scenarios when we need exactly one instance of a class. For example, we need to have an object which contains some configuration for something. In these cases, it is not necessary to create a new object whenever the configuration object is required somewhere in the system.

var singleton = (function() {
    // private singleton value which gets initialized only once
    var config;

    function initializeConfiguration(values){
        this.randomNumber = Math.random();
        values = values || {};
        this.number = values.number || 5;
        this.size = values.size || 10;
    }

    // we export the centralized method for retrieving the singleton value
    return {
        getConfig: function(values) {
            // we initialize the singleton value only once
            if (config === undefined) {
                config = new initializeConfiguration(values);
            }

            // and return the same config value wherever it is asked for
            return config;
        }
    };
})();

var configObject = singleton.getConfig({ "size": 8 });
// prints number: 5, size: 8, randomNumber: someRandomDecimalValue
console.log(configObject);
var configObject1 = singleton.getConfig({ "number": 8 });
// prints number: 5, size: 8, randomNumber: same randomDecimalValue as in first config
console.log(configObject1);

As you can see in the example, the random number generated is always the same, as well as the config values sent in.

It is important to note that the access point for retrieving the singleton value needs to be only one and very well known. A downside to using this pattern is that it is rather difficult to test.

Observer Pattern

The observer pattern is a very useful tool when we have a scenario where we need to improve the communication between disparate parts of our system in an optimized way. It promotes loose coupling between objects.

There are various versions of this pattern, but in its most basic form, we have two main parts of the pattern. The first is a subject and the second is observers.

A subject handles all of the operations regarding a certain topic that the observers subscribe to. These operations subscribe an observer to a certain topic, unsubscribe an observer from a certain topic, and notify observers about a certain topic when an event is published.

However, there is a variation of this pattern called the publisher/subscriber pattern, which I am going to use as an example in this section. The main difference between a classical observer pattern and the publisher/subscriber pattern is that publisher/subscriber promotes even more loose coupling then the observer pattern does.

In the observer pattern, the subject holds the references to the subscribed observers and calls methods directly from the objects themselves whereas, in the publisher/subscriber pattern, we have channels, which serve as a communication bridge between a subscriber and a publisher. The publisher fires an event and simply executes the callback function sent for that event.

I am going to display a short example of the publisher/subscriber pattern, but for those interested, a classic observer pattern example can be easily found online.

var publisherSubscriber = {};

// we send in a container object which will handle the subscriptions and publishings
(function(container) {
    // the id represents a unique subscription id to a topic
    var id = 0;

    // we subscribe to a specific topic by sending in
    // a callback function to be executed on event firing
    container.subscribe = function(topic, f) {
        if (!(topic in container)) {
          container[topic] = [];
        }

        container[topic].push({
            "id": ++id,
            "callback": f
        });

        return id;
    }

    // each subscription has its own unique ID, which we use
    // to remove a subscriber from a certain topic
    container.unsubscribe = function(topic, id) {
        var subscribers = [];
        for (var subscriber of container[topic]) {
            if (subscriber.id !== id) {
                subscribers.push(subscriber);
            }
        }
        container[topic] = subscribers;
    }

    container.publish = function(topic, data) {
        for (var subscriber of container[topic]) {
            // when executing a callback, it is usually helpful to read
            // the documentation to know which arguments will be
            // passed to our callbacks by the object firing the event
            subscriber.callback(data);
        }
    }

})(publisherSubscriber);

var subscriptionID1 = publisherSubscriber.subscribe("mouseClicked", function(data) {
    console.log("I am Bob's callback function for a mouse clicked event and this is my event data: " + JSON.stringify(data));
});

var subscriptionID2 = publisherSubscriber.subscribe("mouseHovered", function(data) {
    console.log("I am Bob's callback function for a hovered mouse event and this is my event data: " + JSON.stringify(data));
});

var subscriptionID3 = publisherSubscriber.subscribe("mouseClicked", function(data) {
    console.log("I am Alice's callback function for a mouse clicked event and this is my event data: " + JSON.stringify(data));
});

// NOTE: after publishing an event with its data, all of the
// subscribed callbacks will execute and will receive
// a data object from the object firing the event
// there are 3 console.logs executed
publisherSubscriber.publish("mouseClicked", {"data": "data1"});
publisherSubscriber.publish("mouseHovered", {"data": "data2"});

// we unsubscribe from an event by removing the subscription ID
publisherSubscriber.unsubscribe("mouseClicked", subscriptionID3);

// there are 2 console.logs executed
publisherSubscriber.publish("mouseClicked", {"data": "data1"});
publisherSubscriber.publish("mouseHovered", {"data": "data2"});

This design pattern is useful in situations when we need to perform multiple operations on a single event being fired. Imagine you have a scenario where we need to make multiple AJAX calls to a back-end service and then perform other AJAX calls depending on the result. You would have to nest the AJAX calls one within the other, possibly entering into a situation known as callback hell. Using the publisher/subscriber pattern is a much more elegant solution.

A downside to using this pattern is difficult testing of various parts of our system. There is no elegant way for us to know whether or not the subscribing parts of the system are behaving as expected.

Mediator Pattern

We will briefly cover a pattern which is also very useful when talking about decoupled systems. When we have a scenario where multiple parts of a system need to communicate and be coordinated, perhaps a good solution would be to introduce a mediator.

A mediator is an object which is used as a central point for communication between disparate parts of a system and handles the workflow between them. Now, it is important to stress out that it handles workflow. Why is this important?

Because there is a large similarity with the publisher/subscriber pattern. You might ask yourself, OK, so these two patterns both help implement better communication between objects… What is the difference?

The difference is that a mediator handles the workflow, whereas the publisher/subscriber uses something called a “fire and forget” type of communication. The publisher/subscriber is simply an event aggregator, meaning it simply takes care of firing the events and letting the correct subscribers know which events were fired. The event aggregator does not care what happens once an event was fired, which is not the case with a mediator.

A nice example of a mediator is a wizard type of interface. Let’s say you have a large registration process for a system you have worked on. Oftentimes, when a lot of information is required from a user, it is a good practice to break this down into multiple steps.

This way, the code will be a lot cleaner (easier to maintain) and the user isn’t overwhelmed by the amount of information which is requested just in order to finish the registration. A mediator is an object which would handle the registration steps, taking into account different possible workflows that might happen due to the fact that each user could potentially have a unique registration process.

The obvious benefit from this design pattern is improved communication between different parts of a system, which now all communicate through the mediator and cleaner codebase.

A downside would be that now we have introduced a single point of failure into our system, meaning if our mediator fails, the entire system could stop working.

Prototype Pattern

As we have already mentioned throughout the article, JavaScript does not support classes in its native form. Inheritance between objects is implemented using prototype-based programming.

It enables us to create objects which can serve as a prototype for other objects being created. The prototype object is used as a blueprint for each object the constructor creates.

As we have already talked about this in the previous sections, let’s show a simple example of how this pattern might be used.

var personPrototype = {
    sayHi: function() {
        console.log("Hello, my name is " + this.name + ", and I am " + this.age);
    },
    sayBye: function() {
        console.log("Bye Bye!");
    }
};

function Person(name, age) {
    name = name || "John Doe";
    age = age || 26;

    function constructorFunction(name, age) {
        this.name = name;
        this.age = age;
    };

    constructorFunction.prototype = personPrototype;

    var instance = new constructorFunction(name, age);
    return instance;
}

var person1 = Person();
var person2 = Person("Bob", 38);

// prints out Hello, my name is John Doe, and I am 26
person1.sayHi();
// prints out Hello, my name is Bob, and I am 38
person2.sayHi();

Take notice how prototype inheritance makes a performance boost as well because both objects contain a reference to the functions which are implemented in the prototype itself, instead of in each of the objects.

Command Pattern

The command pattern is useful in cases when we want to decouple objects executing the commands from objects issuing the commands. For example, imagine a scenario where our application is using a large number of API service calls. Then, let’s say that the API services change. We would have to modify the code wherever the APIs that changed are called.

This would be a great place to implement an abstraction layer, which would separate the objects calling an API service from the objects which are telling them when to call the API service. This way, we avoid modification in all of the places where we have a need to call the service, but rather have to change only the objects which are making the call itself, which is only one place.

As with any other pattern, we have to know when exactly is there a real need for such a pattern. We need to be aware of the tradeoff we are making, as we are adding an additional abstraction layer over the API calls, which will reduce performance but potentially save a lot of time when we need to modify objects executing the commands.

// the object which knows how to execute the command
var invoker = {
    add: function(x, y) {
        return x + y;
    },
    subtract: function(x, y) {
        return x - y;
    }
}

// the object which is used as an abstraction layer when
// executing commands; it represents an interface
// toward the invoker object
var manager = {
    execute: function(name, args) {
        if (name in invoker) {
            return invoker[name].apply(invoker, [].slice.call(arguments, 1));
        }
        return false;
    }
}

// prints 8
console.log(manager.execute("add", 3, 5));
// prints 2
console.log(manager.execute("subtract", 5, 3));

Facade Pattern

The facade pattern is used when we want to create an abstraction layer between what is shown publicly and what is implemented behind the curtain. It is used when an easier or simpler interface to an underlying object is desired.

A great example of this pattern would be selectors from DOM manipulation libraries such as jQuery, Dojo, or D3. You might have noticed using these libraries that they have very powerful selector features; you can write in complex queries such as:

jQuery(".parent .child div.span")

It simplifies the selection features a lot, and even though it seems simple on the surface, there is an entire complex logic implemented under the hood in order for this to work.

We also need to be aware of the performance-simplicity tradeoff. It is desirable to avoid extra complexity if it isn’t beneficial enough. In the case of the aforementioned libraries, the tradeoff was worth it, as they are all very successful libraries.

Next Steps

Design patterns are a very useful tool which any senior JavaScript developer should be aware of. Knowing the specifics regarding design patterns could prove incredibly useful and save you a lot of time in any project’s lifecycle, especially the maintenance part. Modifying and maintaining systems written with the help of design patterns which are a good fit for the system’s needs could prove invaluable.

In order to keep the article relatively brief, we will not be displaying any more examples. For those interested, a great inspiration for this article came from the Gang of Four book Design Patterns: Elements of Reusable Object-Oriented Software and Addy Osmani’s Learning JavaScript Design Patterns. I highly recommend both books.

Further Reading on the Toptal Engineering Blog:

Understanding the basics

JavaScript is asynchronous, supports first-class functions, and is prototype-based.

Design patterns are reusable solutions to commonly occurring problems in software design. They are proven solutions, easily reusable and expressive. They lower the size of your codebase, prevent future refactoring, and make your code easier to understand by other developers.

JavaScript is a client-side scripting language for browsers first created by Brendan Eich for Netscape Navigator by what is now Mozilla.

ECMAScript is a standardized scripting language specification which all modern browsers try to support. There are multiple implementations of ECMAScript, the most popular of which is JavaScript.

A proto-pattern is a pattern-to-be if it passes a certain period of testing by various developers and scenarios where the pattern proves to be useful and gives correct results.

If a design pattern represents good practice, then an anti-pattern represents bad practice. An example of an anti-pattern would be modifying the Object class prototype. Changes to the Object prototype can be seen in all of the objects that inherit from this prototype (that is, almost all objects in JavaScript).

Design patterns can be creational, structural, behavioral, concurrency, or architectural.

Some examples discussed in the article above include the constructor pattern, the module pattern, the revealing module pattern, the singleton pattern, the observer pattern, the mediator pattern, the prototype pattern, the command pattern, and the facade pattern.

Comments

Ruslan Voroshchuk
Awesome, Marko, thanks for the great guide!
Ruslan Voroshchuk
Awesome, Marko, thanks for the great guide!
Вячеслав Москаленко
Nice article. I have a little question though. In the section "Revealing Module Pattern" we can see: getObjects: function() { return objects.slice(); } Why don't just return objects themselves since .slice() doesn't make a deep copy for non-primitives, but rather a shallow copy? So in the end we just have a new array with copies of pointers to the original objects. In that case we can easily manipulate any or original objects as if we were just returning a reference to objects from getObjects method.
Вячеслав Москаленко
Nice article. I have a little question though. In the section "Revealing Module Pattern" we can see: getObjects: function() { return objects.slice(); } Why don't just return objects themselves since .slice() doesn't make a deep copy for non-primitives, but rather a shallow copy? So in the end we just have a new array with copies of pointers to the original objects. In that case we can easily manipulate any or original objects as if we were just returning a reference to objects from getObjects method.
Rakesh mohanta
Nice Article , Thanks for sharing.
Rakesh mohanta
Nice Article , Thanks for sharing.
Londonski Fantom
Great Job. Svaka čast, ovaj članak ide na print :)
Londonski Fantom
Great Job. Svaka čast, ovaj članak ide na print :)
Marko Misura
That is true for objects since they use references, but since I have used primitive types in the example, the copy will actually be deep. I just wanted to demonstrate that we need to make a deep copy, but for simplicity sakes, used slice instead of a more complicated solution. If you need a deep copy for objects as well, you could use JSON.parse(JSON.stringify(objects)) I was wondering will someone catch this, nice one :)
Marko Misura
That is true for objects since they use references, but since I have used primitive types in the example, the copy will actually be deep. I just wanted to demonstrate that we need to make a deep copy, but for simplicity sakes, used slice instead of a more complicated solution. If you need a deep copy for objects as well, you could use JSON.parse(JSON.stringify(objects)) I was wondering will someone catch this, nice one :)
Вячеслав Москаленко
Sure, deep copy is required, but I am not sure if parsing an object's json representation would be faster than copying object recursively in order to create a deep copy. If we have a third party library in our disposal, we can use it to delegate that job. For example, in lodash we can use _.cloneDeep (https://lodash.com/docs/4.17.5#cloneDeep).
Вячеслав Москаленко
Sure, deep copy is required, but I am not sure if parsing an object's json representation would be faster than copying object recursively in order to create a deep copy. If we have a third party library in our disposal, we can use it to delegate that job. For example, in lodash we can use _.cloneDeep (https://lodash.com/docs/4.17.5#cloneDeep).
Вячеслав Москаленко
One more thing regarding example demonstrating prototype pattern. Wouldn't it be nice to simplify it, while keeping main idea the same? For example: function Person(name, age) { this.name = name || 'John Doe'; this.age = age || 26; } Person.prototype = Object.create(personPrototype);
Вячеслав Москаленко
One more thing regarding example demonstrating prototype pattern. Wouldn't it be nice to simplify it, while keeping main idea the same? For example: function Person(name, age) { this.name = name || 'John Doe'; this.age = age || 26; } Person.prototype = Object.create(personPrototype);
Marko Misura
Of course, there are many solutions available. But the important thing is to stress out that it applies to primitive types in my example. I should have put a comment above the line to avoid the confusion.
Marko Misura
Of course, there are many solutions available. But the important thing is to stress out that it applies to primitive types in my example. I should have put a comment above the line to avoid the confusion.
Marko Misura
Yes, you are right. I could have used a more simple example. But this way the people can combine this example with the constructor pattern, wanted to spice things up a little. But of course, your example is also correct and displays the prototype pattern in a simple manner. Also, at the time of writing, I wanted to have an example which goes through constructor => prototype => factory pattern. In the end I changed my mind and didn't display the factory example, so the similar example makes less sense. I wanted to send in multiple prototypes and show how we can easily turn it into a factory or abstract factory pattern, building on the constructor and prototype examples.
Marko Misura
Yes, you are right. I could have used a more simple example. But this way the people can combine this example with the constructor pattern, wanted to spice things up a little. But of course, your example is also correct and displays the prototype pattern in a simple manner. Also, at the time of writing, I wanted to have an example which goes through constructor => prototype => factory pattern. In the end I changed my mind and didn't display the factory example, so the similar example makes less sense. I wanted to send in multiple prototypes and show how we can easily turn it into a factory or abstract factory pattern, building on the constructor and prototype examples.
Marko Misura
Thank you :)
Marko Misura
Thank you :)
Marko Misura
Thanks :)
Marko Misura
Thanks :)
Marko Misura
Hvala :)
Marko Misura
Hvala :)
Julian Bougaev
Could you please elaborate on "A drawback is that we cannot override public members because the functionality is contained within the private function and the public function is only a pointer to the private function, which contains the actual functionality." and provide an example (if possible)? As I understand we can override any property of the JS object.
Julian Bougaev
Could you please elaborate on "A drawback is that we cannot override public members because the functionality is contained within the private function and the public function is only a pointer to the private function, which contains the actual functionality." and provide an example (if possible)? As I understand we can override any property of the JS object.
Marko Misura
I am talking about the exported public parts of both patterns. If you take a look at the module pattern section, you can see that the exported object contains definitions of the exported functions. Now if you take a look at the revealing module pattern section, you can see that the exported object does not contain the function definitions, but rather only pointers to the functions which are defined in the private part of the module. In the first pattern, the module pattern, you can override any of the function definitions and implement your own functions without worrying about introducing bugs into your system, because all of the members are available for override. This is not possible in the revealing module, because you cannot access the private function definitions, possibly introducing bugs on public function overrides which are being used by any of the private functions. You cannot change the private functions behaviour from outside of the module itself.
Marko Misura
I am talking about the exported public parts of both patterns. If you take a look at the module pattern section, you can see that the exported object contains definitions of the exported functions. Now if you take a look at the revealing module pattern section, you can see that the exported object does not contain the function definitions, but rather only pointers to the functions which are defined in the private part of the module. In the first pattern, the module pattern, you can override any of the function definitions and implement your own functions without worrying about introducing bugs into your system, because all of the members are available for override. This is not possible in the revealing module, because you cannot access the private function definitions, possibly introducing bugs on public function overrides which are being used by any of the private functions. You cannot change the private functions behaviour from outside of the module itself.
Arseni
Hm.. Maybe I'm missing something, but as far as I know functions are reference types. That means that you can do like this: var hello = function () {} var goodbye = hello and both, hello and goodbye will point to the same place in memory where function() {} is stored. In both patterns you can do this: collection.addObject = function () { /* something else */} and in both cases you just changed reference from one function (no matter how it was created) to another (also doesn't matter how I create it. could be `collection.addObject = previouslyCreatedFunction`) I can't see any difference and benefits of using revieling module pattern against module pattern.. Again, I'm may be mistaken since you gave it a deep thought, but would be great to have better explanaition..
Arseni
Hm.. Maybe I'm missing something, but as far as I know functions are reference types. That means that you can do like this: var hello = function () {} var goodbye = hello and both, hello and goodbye will point to the same place in memory where function() {} is stored. In both patterns you can do this: collection.addObject = function () { /* something else */} and in both cases you just changed reference from one function (no matter how it was created) to another (also doesn't matter how I create it. could be `collection.addObject = previouslyCreatedFunction`) I can't see any difference and benefits of using revieling module pattern against module pattern.. Again, I'm may be mistaken since you gave it a deep thought, but would be great to have better explanaition..
Arseni
Great job, the article is indeed a good dive in most popular patterns! In removeObject in module pattern it should be collection.indexof(object) > -1 to include removing first element, right?
Arseni
Great job, the article is indeed a good dive in most popular patterns! In removeObject in module pattern it should be collection.indexof(object) > -1 to include removing first element, right?
Marko Misura
Yes, your points are all valid. BUT, imagine you have a scenario where a private function is using another public function or a property, and you try overriding the publicly accessible parts. The private parts would still be the same and would be used as such, even though the public function they use was overridden. Take a look at this example: var revealingModulePatternObject = (function() { var name = "Marko"; var getName = function() { return name; } return { personName: name, getPersonName: getName } })(); revealingModulePatternObject.personName = "John"; // prints out Marko, not John console.log(revealingModulePatternObject.getPersonName()); As seen above, the getName function is using the old value of the name property, set inside the module. However, you COULD work around this behavior but that would defeat the whole purpose of the revealing module pattern.
Marko Misura
Yes, your points are all valid. BUT, imagine you have a scenario where a private function is using another public function or a property, and you try overriding the publicly accessible parts. The private parts would still be the same and would be used as such, even though the public function they use was overridden. Take a look at this example: var revealingModulePatternObject = (function() { var name = "Marko"; var getName = function() { return name; } return { personName: name, getPersonName: getName } })(); revealingModulePatternObject.personName = "John"; // prints out Marko, not John console.log(revealingModulePatternObject.getPersonName()); As seen above, the getName function is using the old value of the name property, set inside the module. However, you COULD work around this behavior but that would defeat the whole purpose of the revealing module pattern.
Marko Misura
Yes, you are right. I forgot to set the >= operator :D My bed.
Marko Misura
Yes, you are right. I forgot to set the >= operator :D My bed.
Arseni
Thanks for your response! I wouldn't expect it to change, since we're using local varaiable in the getName function, not instance property personName. It's pretty straightforward, since strings are passed by value, not reference. Thanks for writing some code - it's easier to clarify my question. I'll take your code and paste it here, but will make it just module pattern, not revealing: var modulePatternObject = (function() { var name = "Marko"; return { personName: name, getPersonName: function() { return name; } } })(); modulePatternObject.personName = "John"; // prints out Marko, not John console.log(modulePatternObject.getPersonName()); It will work the same way as revealingModule that you wrote above. Could you please, using our code from above, give the example for this phrase - "...and you try overriding the publicly accessible parts." As I understand, overriding publicly accessible part means totally create a new function for getPersonName. It will never have access to local var `name`, no matter how you created module, defined or overwrote method for this module.
Arseni
Thanks for your response! I wouldn't expect it to change, since we're using local varaiable in the getName function, not instance property personName. It's pretty straightforward, since strings are passed by value, not reference. Thanks for writing some code - it's easier to clarify my question. I'll take your code and paste it here, but will make it just module pattern, not revealing: var modulePatternObject = (function() { var name = "Marko"; return { personName: name, getPersonName: function() { return name; } } })(); modulePatternObject.personName = "John"; // prints out Marko, not John console.log(modulePatternObject.getPersonName()); It will work the same way as revealingModule that you wrote above. Could you please, using our code from above, give the example for this phrase - "...and you try overriding the publicly accessible parts." As I understand, overriding publicly accessible part means totally create a new function for getPersonName. It will never have access to local var `name`, no matter how you created module, defined or overwrote method for this module.
Marko Misura
Good question! You could do this: var revealingModulePatternObject1 = (function() { var name = "Marko"; var getName = function() { return this.personName; } return { personName: name, getPersonName: getName } })(); revealingModulePatternObject1.personName = "John"; // prints out John console.log(revealingModulePatternObject1.getPersonName()); As I said above, you can write the module in such a way that you can work around it, but it would defeat the purpose of the revealing module.
Marko Misura
Good question! You could do this: var revealingModulePatternObject1 = (function() { var name = "Marko"; var getName = function() { return this.personName; } return { personName: name, getPersonName: getName } })(); revealingModulePatternObject1.personName = "John"; // prints out John console.log(revealingModulePatternObject1.getPersonName()); As I said above, you can write the module in such a way that you can work around it, but it would defeat the purpose of the revealing module.
Arseni
So that is my question - what is the purpose of the revealing module? :) What is the conceptual and most important difference between revealing module and standart module? To me they look the same with just different style of writing code, but the functionality doesn't change at all. But maybe I'm still missing some important part. Would be awesome answering Julian Bougaev question about these sentences: "A drawback is that we cannot override public members because the functionality is contained within the private function and the public function is only a pointer to the private function, which contains the actual functionality. The classic module pattern doesn’t have this problem, as it exposes the function itself, not a pointer to a function." get two examples, where revealing module has a drawback and classic doesn't.
Arseni
So that is my question - what is the purpose of the revealing module? :) What is the conceptual and most important difference between revealing module and standart module? To me they look the same with just different style of writing code, but the functionality doesn't change at all. But maybe I'm still missing some important part. Would be awesome answering Julian Bougaev question about these sentences: "A drawback is that we cannot override public members because the functionality is contained within the private function and the public function is only a pointer to the private function, which contains the actual functionality. The classic module pattern doesn’t have this problem, as it exposes the function itself, not a pointer to a function." get two examples, where revealing module has a drawback and classic doesn't.
Marko Misura
The purpose of the revealing module is the same as is the purpose of the classic module pattern, with the exception of a nicer looking code (this is also debatable, but it looks more neat to me :)). The revealing module pattern is a type of the module pattern, there are at least 3 ways in which you can implement the module pattern, each with it's pros and cons. I have modified the previous examples: // REVEALING MODULE var revealingModulePatternObject = (function() { var name = "Marko"; var getName = function() { return name; } return { name: name, getName: getName } })(); // prints out Marko console.log(revealingModulePatternObject.getName()); revealingModulePatternObject.name = "John"; // prints out Marko, not John, meaning that we DID NOT override the name property console.log(revealingModulePatternObject.getName()); // CLASSIC MODULE var modulePatternObject = (function() { var name = "Marko"; return { name: name, getName: function() { return this.name; } } })(); // prints out Marko console.log(modulePatternObject.getName()); modulePatternObject.name = "John"; // prints out John, meaning that we DID override the name property console.log(modulePatternObject.getName()); The drawback in the RMP is that we would introduce a bug into our system by using the RMP approach. If we would use the classic module approach, as you can see in the second example, we would NOT introduce the same bug into our system. You may think that you would never make a mistake such as that, but try writing an RMP with a few thousands of lines of code. Did I make it clearer this time? :D
Marko Misura
The purpose of the revealing module is the same as is the purpose of the classic module pattern, with the exception of a nicer looking code (this is also debatable, but it looks more neat to me :)). The revealing module pattern is a type of the module pattern, there are at least 3 ways in which you can implement the module pattern, each with it's pros and cons. I have modified the previous examples: // REVEALING MODULE var revealingModulePatternObject = (function() { var name = "Marko"; var getName = function() { return name; } return { name: name, getName: getName } })(); // prints out Marko console.log(revealingModulePatternObject.getName()); revealingModulePatternObject.name = "John"; // prints out Marko, not John, meaning that we DID NOT override the name property console.log(revealingModulePatternObject.getName()); // CLASSIC MODULE var modulePatternObject = (function() { var name = "Marko"; return { name: name, getName: function() { return this.name; } } })(); // prints out Marko console.log(modulePatternObject.getName()); modulePatternObject.name = "John"; // prints out John, meaning that we DID override the name property console.log(modulePatternObject.getName()); The drawback in the RMP is that we would introduce a bug into our system by using the RMP approach. If we would use the classic module approach, as you can see in the second example, we would NOT introduce the same bug into our system. You may think that you would never make a mistake such as that, but try writing an RMP with a few thousands of lines of code. Did I make it clearer this time? :D
Arseni
Kind of... Aggh, I'm not so irritating usually :)) You could introduce the same bug in both modules, no? In classic module you still can write the same getName method with return value of local name and not this.name, introducing the bug. The same works vice versa, you can write in RMP getName to return not name value, but this.name property, eliminating the bug. To me this doesn't look like a bug at all, it seems that if you know what you are doing both options are valid and correct depending on the context and desire to change or not to change name property outside of the module. It doesn't look like specific module pattern would save you from messing name value, you can mess up with it in both variations of pattern the same way. You can either hide it or make it object's property. I mean that phrase about drawback and public method still doesn't make sense to me, since till now we can see that both RMP and CMP are identical in behavior, as you said - it's just preference of the code style.. sorry for the long thread, just thinking maybe I don't get the phrase right..
Arseni
Kind of... Aggh, I'm not so irritating usually :)) You could introduce the same bug in both modules, no? In classic module you still can write the same getName method with return value of local name and not this.name, introducing the bug. The same works vice versa, you can write in RMP getName to return not name value, but this.name property, eliminating the bug. To me this doesn't look like a bug at all, it seems that if you know what you are doing both options are valid and correct depending on the context and desire to change or not to change name property outside of the module. It doesn't look like specific module pattern would save you from messing name value, you can mess up with it in both variations of pattern the same way. You can either hide it or make it object's property. I mean that phrase about drawback and public method still doesn't make sense to me, since till now we can see that both RMP and CMP are identical in behavior, as you said - it's just preference of the code style.. sorry for the long thread, just thinking maybe I don't get the phrase right..
Marko Misura
You are on the right track! The differences between the Revealing Module Pattern and the other variants of the Module Pattern is primarily in how public members are referenced. As a result, RMP is much easier to use and modify, however it could prove fragile in the situations which I demonstrated above. You could implement whatever you need to implement using both module patterns, but in my opinion it is much more code-friendly to use the RMP. I only wanted to point out that care should be applied when using the RMP in scenarios where public members point to private members or when a private function is using a public function because these scenarios could introduce bugs into the system if the author of the code is not aware of this. Don't worry about the thread length, the whole point of the article is to learn the material :)
Marko Misura
You are on the right track! The differences between the Revealing Module Pattern and the other variants of the Module Pattern is primarily in how public members are referenced. As a result, RMP is much easier to use and modify, however it could prove fragile in the situations which I demonstrated above. You could implement whatever you need to implement using both module patterns, but in my opinion it is much more code-friendly to use the RMP. I only wanted to point out that care should be applied when using the RMP in scenarios where public members point to private members or when a private function is using a public function because these scenarios could introduce bugs into the system if the author of the code is not aware of this. Don't worry about the thread length, the whole point of the article is to learn the material :)
Micheal George
Great Read. Thanks for sharing. Do check out our blog-we are a <a href="https://www.fortuneminds.com/java-software-services">Java Software development company </a> in frisco.
Micheal George
Great Read. Thanks for sharing. Do check out our blog-we are a <a href="https://www.fortuneminds.com/java-software-services">Java Software development company </a> in frisco.
Marko Misura
Can do. Thank you :)
Marko Misura
Can do. Thank you :)
Erick Garcia (Let's code)
Hello Marko, thank you for sharing this article, i have learned a lot! Would you mind to give an example for the <b>revealing module pattern</b>, when u say: If we have a public member pointing to a private variable, and try to override the public member from outside the module, the other functions would still refer to the private value of the variable, introducing a bug into our system. Thank you
Erick Garcia (Let's code)
Hello Marko, thank you for sharing this article, i have learned a lot! Would you mind to give an example for the <b>revealing module pattern</b>, when u say: If we have a public member pointing to a private variable, and try to override the public member from outside the module, the other functions would still refer to the private value of the variable, introducing a bug into our system. Thank you
lasya sri
Great to see this complete tutorial.Thank you
bobmyers
I'm wondering how many years or decades it is going to take for the "module pattern" or "revealing module pattern" to die out after ES6 modules have rendered it completely irrelevant?
vikram
Hey Marko, with latest frameworks like React, Angular, Vue etc do I need to really care about design patterns in JS ? I found this interesting article https://hackernoon.com/from-mvc-to-modern-web-frameworks-8067ec9dee65 ( From MVC to modern web frameworks )
Satish Kadyan
you are talking about keeping these framework in mind, there are other nodejs development or core development where design pattern still make sense are in use, also these framework are based on, these design pattern itself.
iiianous
Hi Marko, learned alot about the post but I noticed on the toggle section "What are the main characteristics of JavaScript?" it says "JavaScript is asynchronous". Javascript by nature is synchronous, happening one at a time, and in-order. The asynchronous part happens outside of Javascript.
comments powered by Disqus