JavaScript Singleton Pattern [In-Depth Tutorial]


Olorunfemi Akinlua

JavaScript

Introduction

Design patterns are reusable solutions that address common software development problems. These patterns help developers to write clean, efficient and maintainable code. With such patterns, developers don’t have to start project solutions from scratch.

Singleton pattern is one of the most commonly used patterns in software development. In this article, we will discuss the Singleton pattern in the context of JavaScript.

 

JavaScript Design Patterns

JavaScript is a highly dynamic language that supports a wide range of programming paradigms, including object-oriented programming (OOP). OOP is a software development methodology that revolves around the concept of objects. A design pattern is a reusable solution that solves a common problem. Design patterns are useful in software development because they help us write code that is modular, efficient and maintainable.

 

Classes in JavaScript

JavaScript is a prototype-based language, which means that there are no classes in the traditional sense. However, with the release of ECMAScript 6 (ES6), JavaScript introduced a new syntax for defining classes. This syntax is similar to that of other object-oriented languages such as Java and C++. The class syntax in JavaScript is syntactic sugar that simplifies the process of creating objects with constructors and methods.

 

Implementing Singleton Patterns in JavaScript

A Singleton is a design pattern that restricts the instantiation of a class to a single instance. This means that only one instance of the class can be created, and that instance can be accessed globally. The Singleton pattern is useful in scenarios where we want to limit the number of instances of a class, for example, in a configuration object or a database connection.

To implement a Singleton pattern in JavaScript, we can use the module pattern. The module pattern is a design pattern that encapsulates private data and provides a public interface for accessing that data. In the context of the Singleton pattern, we can use the module pattern to create a single instance of a class.

Here's an example of implementing a Singleton pattern in JavaScript:

const Singleton = (function () {
    let instance;

    function createInstance() {
        const object = new Object({ name: "Singleton Object" });
        return object;
    }

    return {
        getInstance: function () {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        },
    };
})();

const singleton1 = Singleton.getInstance();
const singleton2 = Singleton.getInstance();

console.log(singleton1 === singleton2);

Output

true

In the example above, we define a Singleton object using the module pattern. The Singleton object has a private variable called instance that holds the single instance of the object. We also define a private function called createInstance that creates a new object.

The Singleton object has a public method called getInstance that returns the single instance of the object. The getInstance method checks if the instance variable is null, and if it is, it calls the createInstance function to create a new object.

Finally, we create two instances of the Singleton object using the getInstance method. We then compare the two instances using the === operator, which returns true because both variables point to the same instance of the Singleton object.

Here's another example of the Singleton pattern in JavaScript:

const Singleton = (() => {
    let instance = null;

    class Singleton {
        constructor() {
            if (!instance) {
                instance = this;
            }

            return instance;
        }

        logMessage() {
            console.log("This is a message from the Singleton instance");
        }
    }

    return Singleton;
})();

const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2);
instance1.logMessage();
instance2.logMessage();

Output

true
This is a message from the Singleton instance
This is a message from the Singleton instance

In this example, we use an IIFE (Immediately Invoked Function Expression) to create a Singleton class. The instance variable is used to store the single instance of the class. The constructor method of the Singleton class checks whether an instance of the class already exists. If an instance does not exist, it assigns the current instance to the instance variable.

We then add a logMessage method to the Singleton class to demonstrate that we can add properties and methods to the class. Finally, we create two instances of the Singleton class, instance1 and instance2. We check that they are equal to each other, and we call the logMessage method on each instance.

When we run the code, we can see that instance1 and instance2 are equal to each other, indicating that there is only one instance of the Singleton class. The logMessage method is called on each instance, and we can see that the message is logged to the console.

 

How to create a Singleton instance that can be accessed globally

To create a Singleton instance that can be accessed globally in JavaScript, you can use the module pattern. Here is an example:

var Singleton = (function() {
  var instance;
  
  function createInstance() {
    // private methods and properties go here
    var privateVariable = "I am private";
    
    function privateMethod() {
      console.log(privateVariable);
    }
    
    // public methods and properties go here
    return {
      publicMethod: function() {
        console.log("I am public");
      },
      
      publicVariable: "I am also public",
      
      getPrivate: function() {
        privateMethod();
      }
    };
  }
  
  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// Usage:
var singletonInstance = Singleton.getInstance();
singletonInstance.publicMethod(); // Output: "I am public"
console.log(singletonInstance.publicVariable); // Output: "I am also public"
singletonInstance.getPrivate(); // Output: "I am private"

In this example, we define the Singleton as an immediately invoked function expression (IIFE) that returns an object containing a getInstance method. When the getInstance method is called, it checks if the instance variable is already set and returns it if it is, or creates a new instance using the createInstance function.

The createInstance function defines private methods and properties and returns an object containing public methods and properties. The public methods and properties can be accessed globally by calling Singleton.getInstance().methodName().

Note that the Singleton object is not created until the getInstance method is called for the first time, so it is lazily instantiated. This helps to save resources and improve performance.

 

Can a Singleton pattern be extended in JavaScript

Yes, a Singleton pattern can be extended in JavaScript. One way to achieve this is by using inheritance, which allows you to create a new object that inherits properties and methods from an existing object. Here is an example of how to extend a Singleton pattern in JavaScript using inheritance:

var Singleton = (function() {
  var instance;
  
  function createInstance() {
    // private methods and properties go here
    var privateVariable = "I am private";
    
    function privateMethod() {
      console.log(privateVariable);
    }
    
    // public methods and properties go here
    return {
      publicMethod: function() {
        console.log("I am public");
      },
      
      publicVariable: "I am also public",
      
      getPrivate: function() {
        privateMethod();
      }
    };
  }
  
  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// Extending the Singleton
var ExtendedSingleton = (function() {
  var instance;
  
  function createInstance() {
    // private methods and properties go here
    var privateVariable = "I am private in the extended singleton";
    
    function privateMethod() {
      console.log(privateVariable);
    }
    
    // public methods and properties go here
    return {
      publicMethod: function() {
        console.log("I am public in the extended singleton");
      },
      
      publicVariable: "I am also public in the extended singleton",
      
      getPrivate: function() {
        privateMethod();
      }
    };
  }
  
  // call the parent Singleton's getInstance() method
  var parentInstance = Singleton.getInstance();
  
  // create the new object that inherits from the parent Singleton
  var childInstance = Object.create(parentInstance);
  
  // override the parent Singleton's getInstance() method
  childInstance.getInstance = function() {
    if (!instance) {
      instance = createInstance();
    }
    return instance;
  };
  
  return childInstance;
})();

// Usage
var extendedSingletonInstance = ExtendedSingleton.getInstance();
extendedSingletonInstance.publicMethod(); // Output: "I am public in the extended singleton"
console.log(extendedSingletonInstance.publicVariable); // Output: "I am also public in the extended singleton"
extendedSingletonInstance.getPrivate(); // Output: "I am private in the extended singleton"

In this example, we first define the Singleton pattern as before. Then we define a new object called ExtendedSingleton that inherits from the Singleton object using Object.create(). We then override the getInstance() method of the Singleton object with a new implementation that is specific to the ExtendedSingleton.

When we call ExtendedSingleton.getInstance(), it first calls the parent Singleton's getInstance() method to check if an instance of the Singleton object already exists. If it does, it returns it. If not, it creates a new instance of the ExtendedSingleton object using the createInstance() function defined in the ExtendedSingleton object.

 

How to unit test a Singleton pattern?

When it comes to unit testing a Singleton pattern in JavaScript, the key is to ensure that there is only one instance of the Singleton object throughout the entire test suite. This can be achieved using a technique called dependency injection.

Here's an example of how to unit test a Singleton pattern in JavaScript using dependency injection:

// Singleton module
var Singleton = (function() {
  var instance;
  
  function createInstance() {
    // private methods and properties go here
    var privateVariable = "I am private";
    
    function privateMethod() {
      console.log(privateVariable);
    }
    
    // public methods and properties go here
    return {
      publicMethod: function() {
        console.log("I am public");
      },
      
      publicVariable: "I am also public",
      
      getPrivate: function() {
        privateMethod();
      }
    };
  }
  
  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// Unit test module
var SingletonTest = (function() {
  var testInstance;
  
  return {
    runTests: function(singletonInstance) {
      testInstance = singletonInstance;
      
      test("Singleton instance exists", function() {
        ok(testInstance);
      });
      
      test("Singleton instance is the same throughout the test suite", function() {
        var newInstance = Singleton.getInstance();
        equal(testInstance, newInstance);
      });
      
      test("Public method works", function() {
        sinon.spy(console, "log");
        testInstance.publicMethod();
        sinon.assert.calledWith(console.log, "I am public");
        console.log.restore();
      });
      
      test("Public variable is correct", function() {
        equal(testInstance.publicVariable, "I am also public");
      });
      
      test("Private method works", function() {
        sinon.spy(console, "log");
        testInstance.getPrivate();
        sinon.assert.calledWith(console.log, "I am private");
        console.log.restore();
      });
    }
  };
})();

// Usage
var singletonInstance = Singleton.getInstance();
SingletonTest.runTests(singletonInstance);

In this example, we define a unit test module called SingletonTest that runs a series of tests on the Singleton object. The runTests method takes a singletonInstance argument, which is the instance of the Singleton object that is being tested.

To ensure that there is only one instance of the Singleton object throughout the entire test suite, we pass the instance of the Singleton object to each test using dependency injection.

In each test, we perform a specific action on the singletonInstance object and use assertion methods like ok() and equal() to verify that the expected result is obtained. We also use the sinon library to spy on the console.log method and verify that the correct message is being logged.

By using dependency injection to pass the instance of the Singleton object to each test, we can ensure that there is only one instance of the Singleton object throughout the entire test suite, which is essential for testing a Singleton pattern in JavaScript.

 

Advantages and Disadvantages of the JavaScript Singleton Pattern

One advantage of the Singleton Pattern is that it can help with memory management. By ensuring that only one instance of an object is created, the pattern reduces the amount of memory used in the application. The pattern can also help with code organization by centralizing the management of shared resources and global state in the application.

However, there are also some potential drawbacks to using the Singleton Pattern. For example, it can make testing more difficult because the singleton instance is shared across the application. This can also result in a violation of the Single Responsibility Principle, which states that a class should have only one reason to change. Additionally, using the Singleton Pattern can result in code that is difficult to maintain and modify.

 

Summary

The Singleton pattern is a useful design pattern that limits the number of instances of a class to a single instance. In JavaScript, we can implement the Singleton pattern using the module pattern. The module pattern encapsulates private data and provides a public interface for accessing that data. The Singleton object has a private variable that holds the single instance of the object and a public method that returns the single instance.

 

References

Singleton pattern - Wikipedia
The Singleton Pattern - Learning JavaScript Design Patterns [Book] (oreilly.com)

 

Views: 16

Olorunfemi Akinlua

He is boasting over five years of experience in JavaScript, specializing in technical content writing and UX design. With a keen focus on programming languages, he crafts compelling content and designs user-friendly interfaces to enhance digital experiences across various domains. You can connect with him on LinkedIn.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment

GoLinuxCloud Logo


We try to offer easy-to-follow guides and tips on various topics such as Linux, Cloud Computing, Programming Languages, Ethical Hacking and much more.

Programming Languages

JavaScript

Python

Golang

Node.js

Java

Laravel