Best Design Patterns for writing JavaScript Web applications

Introduction

It is quite appropriate to refer JavaScript design patterns as templates to provide solutions to problems but not quite to say that these patterns can replace the developers.

Object constructors are used to create specific types of objects — both preparing the object for use and accepting arguments which a constructor can use to set the values of member properties and methods when the object is first created.

  1. Object Creation

This is image title

2. Basic Constructors

function person(firstName,lastName){
  
  this.firstName = firstName;
  
  this.lastName = lastName;
  
  this.fullName = function(){
    return this.firstName + " " + this.lastName;
  }
  
}

var person1 = new person('Akash','Pal');
var person2 = new person('Black','Panther');
person1.fullName(); //"Akash Pal"
person2.fullName(); //"Black Panther"
person1 //{firstName: "Akash", lastName: "Pal", fullName: ƒ}
person2 //{firstName: "Black", lastName: "Panther", fullName: ƒ}

This is image title

3. Constructor with prototypes.

This is image title

In this article, I will explore seven best and most popular JavaScript design patterns, which of course most of them will fall under three categories namely; creation design patterns, structural design patterns and behavioral design patterns. A pattern is something like the following image; just to acquaint you into the context.

The Module pattern was originally defined as a way to provide both private and public encapsulation for classes in conventional software engineering.

In JavaScript, the Module pattern is used to further emulate the concept of classes in such a way that we’re able to include both public/private methods and variables inside a single object, thus shielding particular parts from the global scope. What this results in is a reduction in the likelihood of our function names conflicting with other functions defined in additional scripts on the page.

var personModule = (function(){
  
  var firstName;
  var lastName;
  
  return{
    setName(f,l){
      firstName = f;
      lastName = l;
    },
    getName(){
      return firstName + " " + lastName;
    }
  }
  
})();

personModule.setName('akash','pal')
personModule.getName() //"akash pal"

This is image title

An updated pattern where we would simply define all of our functions and variables in the private scope and return an anonymous object with pointers to the private functionality we wished to reveal as public.

var personModule = (function(){
  
  var firstName;
  var lastName;
  
  function setName(f,l){
    firstName = f;
    lastName = l;
  }
  
  function getName(){
    return firstName + " " + lastName;
  }
  
  return{
    setName:setName,
    getName:getName
  }
  
})();

personModule.setName('akash','pal');
personModule.getName(); //"akash pal"

The Singleton pattern is thus known because it restricts instantiation of a class to a single object. Classically, the Singleton pattern can be implemented by creating a class with a method that creates a new instance of the class if one doesn’t exist. In the event of an instance already existing, it simply returns a reference to that object.

var singleton = (function(){

  var instance;
  
  function init(){
    
    var name;
    
    this.setName = function(name){
       this.name = name;
    }
    
    this.getName = function(){
      return this.name;
    }
    
    return{
      setName:setName,
      getName:getName
    }
      
  }
  
  function getInstance(){
    
    if(!instance){
      instance = init();
    }
    
    return instance;
  }
    
  return{
    getInstance:getInstance
  }  
  
})();


var one = singleton.getInstance();
var two = singleton.getInstance();

//the two instance are same
one == two //true

one.setName('Akash');
two.getName(); //"Akash"

This is image title

The Observer is a design pattern where an object (known as a subject) maintains a list of objects depending on it (observers), automatically notifying them of any changes to state.

  • Subject: maintains a list of observers, facilitates adding or removing observers
  • Observer: provides an update interface for objects that need to be notified of a Subject’s changes of state
  • ConcreteSubject: broadcasts notifications to observers on changes of state, stores the state of ConcreteObservers
  • ConcreteObserver: stores a reference to the ConcreteSubject, implements an update interface for the Observer to ensure state is consistent with the Subject’s

Publish/Subscribe Pattern

The Observer pattern requires that the observer (or object) wishing to receive topic notifications must subscribe this interest to the object firing the event (the subject).

The Publish/Subscribe pattern however uses a topic/event channel which sits between the objects wishing to receive notifications (subscribers) and the object firing the event (the publisher). This event system allows code to define application specific events which can pass custom arguments containing values needed by the subscriber. The idea here is to avoid dependencies between the subscriber and publisher.

This differs from the Observer pattern as it allows any subscriber implementing an appropriate event handler to register for and receive topic notifications broadcast by the publisher.

This is image title

A Mediator is an object that coordinates interactions (logic and behavior) between multiple objects. It makes decisions on when to call which objects, based on the actions (or inaction) of other objects and input.

This is image title

We can think of the prototype pattern as being based on prototypal inheritance where we create objects which act as prototypes for other objects. The prototype object itself is effectively used as a blueprint for each object the constructor creates. If the prototype of the constructor function used contains a property called name for example (as per the code sample lower down), then each object created by that same constructor will also have this same property.

Real prototypical inheritance, as defined in the ECMAScript 5 standard, requires the use of Object.create

function person(firstName,lastName){
  
  this.firstName = firstName;
  
  this.lastName = lastName;
  
}

person.prototype.fullName = function(){
    return this.firstName + " " + this.lastName;
}

var person1 = new person('Akash','Pal');
var person2 = new person('Black','Panther');
person1 //{firstName: "Akash", lastName: "Pal"}
person2 //{firstName: "Black", lastName: "Panther"}
person1.fullName() //"Akash Pal"
person2.fullName() //"Black Panther"

This is image title

The prototype pattern without directly using Object.create

This is image title

The Command pattern aims to encapsulate method invocation, requests or operations into a single object and gives us the ability to both parameterize and pass method calls around that can be executed at our discretion. In addition, it enables us to decouple objects invoking the action from the objects which implement them, giving us a greater degree of overall flexibility in swapping out concrete classes(objects).

var name = {
  fName:'aaa',
  lName:'bbb',
  setName:function(fName,lName){
    this.fName = fName;
    this.lName = lName;
  },
  getName:function(){
     return this.fName + " " + this.lName;
  }
}

name.execute = function(key){
   var methodName = name[key];
   var functionParamsArray = [].splice.call(arguments,1);
   return methodName.apply(name,functionParamsArray);   
}

name.execute('setName','Akash','Pal');
console.log(name.execute('getName'));//Akash Pal

This is image title

Facades are a structural pattern which can often be seen in JavaScript libraries like jQuery where, although an implementation may support methods with a wide range of behaviors, only a “facade” or limited abstraction of these methods is presented to the public for use.

Facades can also be integrated with other patterns such as the Module pattern.

This is image title

The Factory pattern is another creational pattern concerned with the notion of creating objects. Where it differs from the other patterns in its category is that it doesn’t explicitly require us to use a constructor. Instead, a Factory can provide a generic interface for creating objects, where we can specify the type of factory object we wish to be created.

function Bike(options){
  this.wheels = 2;
  this.color = options.color;
}

function Car(options){
  this.wheels = 4;
  this.color = options.color;
}

function VehicleFactory(){}

VehicleFactory.prototype.createVehicle = function(options){
		
    switch(options.type){
    	case 'Bike': 
          this.vehicleClass = Bike;
      break;
      case 'Car': 
          this.vehicleClass = Car;
      break;
      default: 
          this.vehicleClass = Bike;
    }
    
    return new this.vehicleClass(options);
}

var vehicleFactory = new VehicleFactory();

var bike = vehicleFactory.createVehicle({
	type:'Bike',
  color:'black'
});

console.log(bike); //Bike {wheels: 2, color: "black"}

var car = vehicleFactory.createVehicle({
	type:'Car',
  color:'white'
});

console.log(car); //Car {wheels: 4, color: "white"}

This is image title

Mixins are classes which offer functionality that can be easily inherited by a sub-class or group of sub-classes for the purpose of function re-use.

function Person(firstName,lastName){
  this.firstName = firstName; 
  this.lastName = lastName;
}

Person.prototype.fullName = function(){
    return this.firstName + " " + this.lastName;
}

function Superhero(firstName,lastName,powers){
  //super call
	Person.call(this,firstName,lastName);
  this.powers = powers;
}

Superhero.prototype = new Object(Person.prototype);

Superhero.prototype.showPowers = function(){
		return this.powers;
}

var superhero1 = new Superhero('Iron','Man',['Flying suit','Jarvis']);
console.log(superhero1.fullName() + '-' + superhero1.showPowers()); //Iron Man-Flying suit,Jarvis

var superhero2 = new Superhero('Captain','America',['strength','endurance','healing']);
console.log(superhero2.fullName() + '-' + superhero2.showPowers()); //Captain America-strength,endurance,healing

This is image title

This articles includes examples derived from the below publication including my own inference of the patterns with the intention of simplifying the understanding of the patterns.

Conclusion

It is beneficial for JavaScript developers to use design patterns. Some major advantages of using design patterns include project maintainability and also cuts off unnecessary work on the development cycle. Even though JavaScript design patterns can provide solutions to complex problems, needless to say, rapid development and productivity, it is improper to conclude that these design patterns can replace the developers.

Thanks for reading, Hope this tutorial will surely help and you! Please share if you liked it!

Related Articles

The Comprehensive Guide to JavaScript Design Patterns

Top 10 JavaScript Design Patterns Every Developer Should Know

10 JavaScript Design Patterns You Should Know

7 best JavaScript Design Patterns You Should Know

#javascript #design-pattern #web-development

Best Design Patterns for writing JavaScript Web applications
17 Likes185.85 GEEK