6

I am working on a large project where I have multiple managers to handle different tasks, I need an only a single object of these managers to be created when I start the app,

I came across this method of Singleton creation

class QuestionnaireManager {

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

Is this an acceptable way, is there any downside, I am coming from JAVA Kotlin background and this seems to simple to be true where we have so much to deal in case of singletons in other languages. (Most of those cases have to deal with multi-threading but as JS is single-threaded so I think this would be sufficient way)

Still need opinion on best practices, or any other Dependency Injection methods where we don't even rely on Singleton but create the object once and reuse all over the project with dependency injections.

I would like to know the opinion of sensie in JS.

0

6 Answers 6

18

That ain't the right way to implement Singleton in ES6. The correct way:

class QuestionnaireManager {
  constructor() {
    if (QuestionnaireManager._instance) {
      throw new Error("Singleton classes can't be instantiated more than once.")
    }
    QuestionnaireManager._instance = this;

    // ... your rest of the constructor code goes after this
  }
}

var managerOne = new QuestionnaireManager()
var managerTwo = new QuestionnaireManager() // Throws error

Or, if you don't want an error to be thrown on second instance creation you can just return the last instance, like so:

class QuestionnaireManager {
  constructor() {
    if (QuestionnaireManager._instance) {
      return QuestionnaireManager._instance
    }
    QuestionnaireManager._instance = this;

    // ... your rest of the constructor code goes after this
  }
}

var managerOne = new QuestionnaireManager()
var managerTwo = new QuestionnaireManager()

console.log(managerOne === managerTwo) // logs "true"

3
  • How is this way technically different from what I was doing ? can you please elaborate, also I usually put export new QuestionnaireManager() at the bottom, so it is easy to just use functions inside QuestionnaireManager() without creating a specific object, is it also a right approach? Jan 20, 2020 at 11:42
  • for example: QuestionnaireManager.doSomething(), as while exporting only we have created the object, which is a singleton so no need to create a new object Jan 20, 2020 at 11:43
  • 1
    Well, that's okay to export the instance if it serves your purpose but if you see the OOP way it is inhibiting the features of inheritance. Let's say you want to extend this QuestionnaireManager class in the future to some AdvancedQuestionnaireManager class, you won't really be able to do that as it's the class only that can be extended and not the instance itself that you have exported. Jan 20, 2020 at 12:56
5
// Singleton.js

class Singleton {
    constructor(){
        if(Singleton._instance){
            console.warn("already created!");
            return Singleton._instance;
        }

        Singleton._instance = this;

        console.log("singleton created");

        this._createdTime = new Date();
    }

    static instance() {
        if(!Singleton._instance){
            return new Singleton();
        }

        return Singleton._instance;
    }

    createdTime() {
        return this._createdTime.toISOString();
    }
}

Singleton._instance = null;

export default Singleton;

// main.js

import Singleton from "./Singleton"

const a = new Singleton();
const b = new Singleton();
const c = Singleton.instance();

console.log(a.createdTime());
console.log(b.createdTime());
console.log(c.createdTime());

Output would be enter image description here

4

In javascript you can export an instance of a class to make a singleton

// questionnaire-manager.js
class QuestionnaireManager {

  constructor() {
  }
}

module.exports = new QuestionnaireManager()

Then when you call require('questionnaire-manager') you'll always get the same instance.

0

Like Mikel B.'s answer only in a shorter syntax

module.exports = new class foo {..}
1
0
class Singleton {
  constructor() {
    if (!Singleton.instance) {
      // Create a new instance of the class
      this.data = [];
      Singleton.instance = this;
    }

    return Singleton.instance;
  }

  // Add a method to the class
  addData(data) {
    this.data.push(data);
  }
}

// Create a new instance of the class
const instance1 = new Singleton();
instance1.addData('Hello');

// Try to create a second instance of the class
const instance2 = new Singleton();

console.log(instance1 === instance2); // true
console.log(instance1.data); // ['Hello']
console.log(instance2.data); // ['Hello']
1
  • Answer needs supporting information Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – moken
    May 1, 2023 at 1:59
-1

You need a static property, not instance property this.instance. It will be accessable by QuestionnaireManager.instance reference. But... it is sooo rare case to implement classical GOF singleton in Javascript... kind of enforcing yourself to develop UI in vim and feel yoursefl as "true develper" :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.