Create singleton classes in JS: Object.freeze(new function(){...})

Using Singleton Creation for a Large Project in JavaScript

When working on a large project where multiple managers are needed to handle different tasks, a single object of these managers should be created when the app is started. One way to achieve this is through a Singleton creation. The following code provides an example of how this could be done using JavaScript:

class QuestionnaireManager {

  constructor() {
    if (this.instance) {
      return;
    }
    this.instance = this;
  }
}

There are some potential downsides to using this method, as it may be too simple for those coming from a JAVA or Kotlin background, where multi-threading is a factor. As JavaScript is single-threaded, however, this may be suitable.

I would like to know the opinion of experts in JavaScript regarding best practices for Singleton creation, or any other Dependency Injection methods which would allow the object to be created once and reused throughout the project with dependency injection.

There are multiple ways to implement Singleton creation in JavaScript, and the approach shown in the code provided is a valid one. However, some experts recommend using a closure-based approach to create a Singleton object in JavaScript, as it provides better encapsulation and protects the object from being modified from outside the class.

Here’s an example of how this could be done:

const QuestionnaireManager = (function() {
  let instance;

  function createInstance() {
    // constructor logic here
    return {
      // methods and properties here
    };
  }

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

This closure-based approach uses an Immediately Invoked Function Expression (IIFE) to create a private scope where the instance variable is declared. The createInstance function is defined inside the IIFE and is used to construct the Singleton object. The getInstance method is exposed through the IIFE and is used to get a reference to the Singleton object. If the instance variable is not set, the createInstance function is called to create the object.

Another approach is to use a dependency injection framework like InversifyJS or Awilix, which can manage the creation and injection of dependencies throughout the project. These frameworks allow for better modularity and maintainability of the codebase.