×
As programming languages and programming in general has evolved and applications have grown larger and larger, best practices around designing the structure of our code have been established. Patterns are reusable solutions to solve potential issues when building applications. There are many different types of design patterns that can be used to solve a multitude of problems when building software.
When reading about design patterns, you will see the term class
and instance
quite frequently. It is important to note that JavaScript does not have built in class support, so we use objects and functions to mimic this behavior.
There are three types of design patterns: creational, structural, and behavioral.
Creational - these patterns are focused on object creation.
Structural - these patterns are focused on managing relationships between objects. Structural patterns ensure that when one part of your application changes, it does not affect other parts of your application.
Behavioral - these patterns are focused on managing communication between objects.
Let's first examine a few creational design patterns:
The constructor pattern is a creational pattern for making objects and is one that we have seen before! The constructor pattern makes use of a function called a constructor
to create objects. Here is a small example of the constructor pattern with the prototype object (which is shared amongst all objects created from this constructor function using the new
keyword):
function Person(firstName, lastName){ this.firstName = firstName; this.lastName = lastName; } var matt = new Person("Matt", "Lane"); var elie = new Person("Elie", "Schoppik"); var tim = new Person("Tim", "Garcia"); matt.__proto__ === elie.__proto__ // true tim.constructor === Person // true
Before we examine the module pattern, let's redefine what a "module" is. A module is a self-contained (or encapsulated), reusable piece of code. The module pattern is an alternative to creating a class, and allows us to emulative native class functionality present in other programming languages. With modules, we can declare public and private variables and methods, and avoid variable collisions in the global scope. The module pattern makes use of closure
to create private variables and uses an IIFE
(Immediately Invoked Function Expression) for an easier syntax when accessing the module. Here is an example of the module pattern
var myModule = (function() { // A private variable inside the scope of the IIFE that is var privateVariable = "secret"; // A private function inside the scope of the IIFE function privateFunction() { console.log("You just called the private function!"); }; // everything returned in the object is accessible publicly return { // A public variable publicVariable: "You can see me!", // A public function utilizing privates displayPrivateVariable: function() { console.log(privateVariable); }, invokePrivateFunction: function() { privateFunction(); } }; })(); myModule.publicVariable; // "You can see me!" myModule.displayPrivateVariable(); // "secret" myModule.privateFunction; // undefined myModule.privateVariable; // undefined myModule.invokePrivateFunction(); // "You just called the private function!"
We can also pass values to our modules from other global modules as parameters. This idea is known as importing
.
var myModule = (function(j, r) { // we now have imported jQuery and React and named them as j and r in our module! })(jQuery, React);
The module pattern is great way to create private variables and encapsulation in our JavaScript code. A potential disadvantage is that private variables are not very flexible, which can make testing modules challenging and fixing bugs difficult when there is an issue with private variables and methods.
You can read much more about the module pattern here.
A slight variation on the module pattern is the revealing module pattern. In this pattern, public functions are defined before the return {}
inside of the module and inside the return {}
we use references to previously defined functions. This simplifies the return statement and can make the code easier to read. Let's see an example.
var myRevealingModule = (function(){ var start = 0; function incrementNumberPrivate(){ start++; } function incrementNumberPublic(){ incrementNumberPrivate(); } function initialize(){ incrementNumberPublic(); } function getPrivateNumber(){ return start; } return { init: initialize, add: incrementNumberPublic, status: getPrivateNumber } })()
The singleton pattern is a bit different than the constructor and module patterns even though it is also a Creational pattern. In traditional object oriented languages, the singleton pattern creates a new instance, only if one does not exist already (singleton => "single instantiation"). If the instance exists, the pattern returns a reference to the instance. Therefore you can only create a single instance, or in JavaScript a single object from this pattern. The singleton pattern is used heavily in front-end frameworks like Angular.
Let's see an example:
var firstSingleton = (function(){ var instance; // this code will be executed ONCE function initialize(){ var count = 0; var privateName = "Samuel Singleton"; function privateMethod(){ return "Your name is " + privateName; } return { sayMyName: privateMethod, increment: function(){ count++; return count; }, getCount: function(){ return count; } } } // let's see if we need to call the initialize function return { findOrCreateInstance: function(){ if(!instance){ instance = initialize(); } return instance; } } })() var one = firstSingleton.findOrCreateInstance(); var two = firstSingleton.findOrCreateInstance(); one === two; // true one.increment(); // 1 one.increment(); // 2 one.increment(); // 3 two.getCount(); // 3
The Singleton pattern is very useful when you only want one instance possibly created, but it can be difficult to test and when used too heavily throughout a codebase, it can actually be a sign of poor design.
The Facade pattern is used quite heavily in jQuery and involves presenting an outward appearance that hides underlying complexity. The idea is that using this pattern, we can provide a simple looking API and obscure the complexity from others. Some examples of the Facade pattern in jQuery are .css()
,.animate()
and other abstractions like .getJSON()
, .get(),
and .post()
. Take a look at one of the potential implementations of $(document).ready
here and you can see just how much complexity is hidden from what appears to be a simple method.
In the facade pattern we abstract quite a bit of detail when the facade function is called. When you find yourself using a library or framework and using many predetermined values (especially for keys in objects), you very well may be using a facade!
The observer pattern is where an object (the subject) has a list of objects that depend on it (observers/subscribers) and automatically notifies the observers when there are any changes. The subject has the ability to subscribe and unsubscribe objects from the list as well. There is also a pattern called pub/sub (publish/subscribe), which is very similar to the observer Pattern except in a pub/sub model there is additional data that sits between the subject and observer.
You can find some great examples of the observer pattern here
The Observer pattern is quite common in popular JavaScript libraries like RxJS and Redux. You have also already seen many examples of the Observer pattern with jQuery methods like on()
and off()
to subscribe and unsubscribe to events.
There are quite a few design patterns that we have not seen, you can learn more about them with these resources.
https://scotch.io/bar-talk/4-javascript-design-patterns-you-should-know
http://code.tutsplus.com/tutorials/understanding-design-patterns-in-javascript--net-25930
https://addyosmani.com/resources/essentialjsdesignpatterns/book/
When you're ready, move on to Anti Patterns in JavaScript