Categories
JavaScript Design Patterns

Basic JavaScript Design Patterns- Object Creation

Spread the love

JavaScript lets us do a lot of things. It’s sometimes too forgiving in its syntax.

To organize our code, we should use some basic design patterns. In this article, we’ll look at some basic object creation patterns that we may use.

Singleton

The singleton pattern is where we create a single instance of a class.

Since we can create object literals without a constructor in JavaScript, we can create an object easily as follows:

const obj = {  
  foo: 'bar'  
};

obj will also be a standalone object, so defining an object literal follows the singleton pattern.

If we create a new object that has the same structure, we’ll get a different object.

For instance, if we create a new object:

const obj2 = {  
  foo: 'bar'  
};

Then when we write:

obj2 === obj

to compare 2 objects, then that’ll return false since they’re different references.

Using new

We can also create a singleton object even if we create them from constructors or classes.

For instance, we can write:

let instance;  
class Foo {  
  constructor() {  
    if (!instance) {  
      instance = {  
        foo: 'bar'  
      };  
    }  
    return instance;  
  }  
}

Then if we create 2 Foo instances:

const foo1 = new Foo();  
const foo2 = new Foo();

Then when we compare them:

console.log(foo1 === foo2);

We see true logged.

We check if the instance is created and then return it as is if it is. Otherwise, we set it to an object.

Since instance won’t change after it’s set, all instances are the same.

We can make the instance variable private by putting it in an IIFE.

For instance, we can write:

const Foo = (() => {  
  let instance;  
  return class {  
    constructor() {  
      if (!instance) {  
        instance = {  
          foo: 'bar'  
        };  
      }  
      return instance;  
    }  
  }  
})()

Now we can only access the returned instance rather than looking at the constructor.

An Instance in a Static Property

Alternatively, we can put the instance of the singleton in a static property of the constructor or class.

For instance, we can write:

class Foo {  
  constructor() {  
    if (!Foo.instance) {  
      Foo.instance = {  
        foo: 'bar'  
      };  
    }  
    return Foo.instance;  
  }  
}

This way, we set the public instance property of the class Foo to return the instance if it exists. Otherwise, it’ll create it first.

Now if we write:

const foo1 = new Foo();  
const foo2 = new Foo();

console.log(foo1 === foo2);

We get the same result as before.

Instance in a Closure

We can also put the singleton instance in a closure.

For instance, we can write:

function Foo() {  
  const instance = this;  
  this.foo = 'bar';  
  Foo = function() {  
    return instance;  
  }  
}

We can write a constructor function that gets reassigned to itself at the end of the function.

This will let us return the instance while using this to assigning instant variables.

This won’t work with the class syntax since it’s created as a constant, so we can’t reassign it to a new value.

Factory

We can create a factory function to create an object.

A factory function is just a regular function that we can use to create objects.

It’s useful for performing repeated operations when setting up similar objects.

It also offers a way for users of the factory to create objects without the specific class at compile time.

For instance, we can create our own factory function as follows:

class Animal {}  
class Dog extends Animal {}  
class Cat extends Animal {}  
class Bird extends Animal {}

const AnimalMaker = type => {  
  if (type === 'dog') {  
    return new Dog()  
  } else if (type === 'cat') {  
    return new Dog()  
  } else if (type === 'bird') {  
    return new Dog()  
  }  
}

The code above has the AnimalMaker factory function.

It takes the type parameter which allows us to create different subclasses given the type .

So we can call it as follows:

const animal = AnimalMaker('dog');

to create a Dog instance.

We can also add methods as we wish into the classes:

class Animal {  
  walk() {}  
}  
class Dog extends Animal {  
  bark() {}  
}  
class Cat extends Animal {}  
class Bird extends Animal {}

const AnimalMaker = type => {  
  if (type === 'dog') {  
    return new Dog()  
  } else if (type === 'cat') {  
    return new Dog()  
  } else if (type === 'bird') {  
    return new Dog()  
  }  
}

This will also work.

Conclusion

We can create objects with a single instance y using object literals or checking if the instance of the class exists and create it if it doesn’t exist.

Factory functions are useful for creating similar objects.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *