Sysleaf

Understanding various Instantiation pattern in Javascript

. .
Understanding various Instantiation pattern in Javascript

Introduction

There are different ways to create an instance of an object in Javascript that we call instantiation pattern. Each pattern has its own pros and cons that we will see in this article.

We can think of an object in Javascript as real world object. Real world object has two characteristics, namely state and behavior. Let’s take an example of a house. Each house will have state (color, door) and behavior(opening door, closing door). In javascript, we will call state as properties and behavior as method.

In this article, we will try to implement this house as an example using various instantiation pattern and see each one’s pros and cons.

Object Literal

This is the simplest way to create an object in Javascript. Object properties/method are wrapped inside curly braces as a list of comma separated key-value pairs.

var red_house = {
  door: "open",
  color: "red",
  openDoor: function(){ this.door = "open" },
  closeDoor: function(){ this.door = "close" }
};

var blue_house = {
  door: "open"
  color: "blue",
  openDoor: function(){ this.door = "open" },
  closeDoor: function(){ this.door = "close" }
};

Pros

  1. Simple: It is very simple and basic way to create an object.
  2. Single Instance: Good for creating a single instance of a different object type.
  3. Readable: Code looks clean, it is clear to read and easy to understand.

Cons

  1. No Multiple Instance: It is not good for creating multiple instance of same object type.
  2. Non-Sharable Code: Not good for creating multiple instances of an object that want to share some of its properties/method as each instance will have its own separate copy of properties/method.
  3. Memory Inefficent: Since every instance has its own copy of properties/method in memory, it is memory inefficient.
  4. Verbose: It is very verbose, because each time we want to create a different instance of the same object, we have to type properties/method name apart from properties/method value.

Functional

In this pattern, we still create an instance using object literal but, this logic of instantiation is put inside a function. Whenever we call that function, it creates a new object and returns it. It also gives us the ability to create a new object with same or different properties/method value depending on function parameter passed.

var House = function(color){
    var obj = {};
    obj.color = color;
    obj.door = 'open'
    obj.openDoor = function(){ obj.door = 'open' };
    obj.closeDoor = function(){ obj.door = 'close' };
    return obj;
}

var red_house = House('red');
var blue_house = House('blue');

Pros

  1. Multiple Instance: This is simple and basic way to create multiple instance of same object type.

Cons

  1. Non-sharable Code: This pattern also has the same problem as ‘object literal’ pattern. It is not good if we want to create multiple instances of an object that want to share common properties/method because each instance will have its own separate copy of properties/method. i.e In above code, red_house and blue_house has same method openDoor() and closeDoor(), So ideally these methods should be shared with all instances but it’s not possible with this pattern.
  2. Memory Inefficent: Same reason as above.

Functional Shared

This pattern is very similar to above except the way we attach the shareable properties/method. It tries to solve the problem ‘Non-sharable’ found in above ‘Functional’ pattern.

So in below example, we have to make sure that method openDoor and closeDoor is shared across instances instead of duplicating it across instance. To do this, we are attaching these method on a single separate object houseMethods then we are using its reference in instantiation code. Now we have a single copy of method in memory across all instances.

var House = function(color){
    var obj = {};
    obj.color = color;
    obj.openDoor = houseMethods.openDoor;
    obj.closeDoor = houseMethods.closeDoor;
    return obj;
}

var houseMethods = {}
houseMethods.openDoor = function(){ this.door = 'open' };
houseMethods.closeDoor = function(){ this.door = 'close' };

var red_house = House('red');
var blue_house = House('blue');

Pros

  1. Memory efficient: This is more memory efficient compared to previous ‘Functional’ pattern..

Cons

  1. Prone to error: In above code, After creating some inital instance, If we modify the shared method i.e openDoor() afterward create some new instance, then old and new instace will refer to different shared method openDoor(). Generally, this is not what we expect. We will see below pattern, which solve this problem.

Prototypal

If you know prototypical inheritance in Javascript, then it is easy to understand. It tries to solve the problem found in above pattern. Every object in Javascript is created from another object. i.e If object2 is created from object1, then object1 will be called prototype of object2. object2 will inherit all the properties/method of object1 through prototypical chain.

Let’s say method1 is a method of object1, not object2. So now if we call object2.method1() then Javascript engine will first check if object2 has method method1 as its direct method, If not then it will look into object2.prototype which is object1.

Such way of looking a method in prototypical inheritance is also called delegation. Delegation is a way to delegate object method to its parent prototype in a prototypical chain until it finds the targeted method.

var House = function(color){
    var obj = Object.create(House.prototype)
    obj.color = color;
    obj.door = 'open';
    return obj;
}

House.prototype.openDoor = function(){ this.door = 'open' };
House.prototype.closeDoor = function(){ this.door = 'close' };

var red_house = House('red');

Pros

  1. Less prone to error: It solves the problem found in above pattern.
  2. Purist: Many purist javascript developers prefer this pattern of instantiation compare to another pattern.

Cons

  1. More Code: It is not actually cons, but there are other new alternative patterns where we can achieve the same using less code. See subsequent section for this.

Pseudo classical

It was first little attempt to bring the ‘Java inspired’ object oriented keyword in Javascript by introducing keyword like new and this. In this pattern, we create an object by calling a function with new keyword. A function which is called with new keyword is called constructor function. Keyword new is very powerful, it sets the context of this. Missing new keyword is also the main source of bug as it changes the context of this.

var House = function(color){
    this.color = color;
    this.door = 'open';
}

House.prototype.openDoor = function(){ this.door = 'open' };
House.prototype.closeDoor = function(){ this.door = 'close' };

var red_house = new House('red');
var blue_house = new House('blue');

Pros

  1. Concise: It is a very concise way to create an object in Javascript. Most of the developer use this pattern for object instantiation.

Cons

  1. new keyword: It is easy to forget to put new keyword before constructor function call, which might be the cause of a serious bug.

ES6 Pseudo classical

Whatever we are trying to do in all above pattern is nothing but mimicking the Java class. Now fortunately or unfortunately Java inspired keyword like class, constructor, extend etc has landed natively in javascript from ES6/ES2015.

Class House{
    constructor(color){
        this.color = color;
        this.door = 'open';
    }
    openDoor() { this.door = 'open' };
    closeDoor() { this.door = 'close' }
}

var red_house = new House('red');

Pros

  1. Latest: This is the new and latest way to create an instance of an object.
  2. Java Inspired: If you know Java, then it will be easy for you to understand this syntax.

Cons

  1. Ambigious: We know that Javascript does not really have a concept of class. We also know that Javascript does not support classical inheritance instead it has its own inheritance called Prototypical inheritance. So bringing keyword like class, constructor and extend only increase the confusion.

  2. Non-Functional: In Javascript, we can write pure functional code which has its own power and advantage but such syntax is against the pattern of functional programming. See the links given in reference section for more details.

Reference

  1. See curated list of resources on why ES6 (aka ES2015) classes are NOT awesome