Described in Design Patterns from E. Gamma, R. Helm, R. Johnson, and J. Vlissides, the pattern “ensures a class only has one instance, and provide a global point of access to it.” It’s often used when you want to write a Service, a Factory, or any software component which needs to be unique.

By adding unicity to an instance, you provide a way to share any information or feature between two or more components in your code. The instance is the same, so all related data too.

Base: the Java pattern but with JS

So we have to implement the pattern? Huh, it’s ok. JavaScript has classes. It will be easy.

We reproduce the good ol’ pattern with ES6 Classes. We create a ‘static getInstance()’ to get the singleton instance, and we export the class.

So Java-ish!

Pattern

class Translator {
  static _instance;

  static getInstance() {
    if (!Translator.instance) {
      Translator.instance = new Translator();
    }

    return Translator.instance;
  }

  constructor() {
    this.language = "fr";
  }

  getTranslation(text) {
    // doSomething
  }
}

export default Translator;

Usage

import Translator from "./Translator";

const translation = Translator.getInstance().getTranslation("NEXT");

Problems

  • No possibility to control the constructor: in the Java version, we must set the constructor as ‘private’ to block any ‘new Translator()’ call out of the class itself. This is not possible in JS.
  • Needs to call getInstance() after import: oh lord, if we want to use something as verbose as Java, use Java.

Upgrade: the pattern with ES modules

ES Modules (especially the import/export syntax) allow us to export a specific datum during the export. Exported datum will be the same anywhere the datum is imported. With this information, we can now remove all the static stuff and export an instance of our Translator. Each time we will import the Translator module, the JS engine will provide this instance. And like any singleton, all data of this instance are preserved among files.

Pattern

class Translator {
  constructor() {
    this.language = "fr";
  }

  getTranslation(text) {
    // doSomething
  }
}

export default new Translator();

Usage

import Translator from "./Translator";

const translation = Translator.getTranslation("NEXT");

This one is the implementation I like to use. You have to code your class and export an instance. Nothing complicated, and it’s powerful to create services in a React application or a Node.JS application.

Note: it also works with the “module.exports” syntax of Node.JS.

Upgrade bonus: the pattern without classes

Yeah, you can use an Object-Oriented pattern without the fundamental of the paradigm. You have to apply the same technique seen before but with any object. I encapsulate the whole code in a function to avoid adding variables in the global context (in proper terms, a closure).

Pattern

export default (() => {
  let language = "fr";

  function getTranslation(text) {
    // doSomething
  }

  function setLanguage(newLang) {
    language = newLang;
  }

  return {
    getTranslation,
    setLanguage,
  };
})();

Usage

import Translator from ./Translator;

const translation = Translator.getTranslation(NEXT);

I hope you found this short article useful. I’ll probably write some others patterns during the next weeks, so don’t hesitate to follow the company on Twitter.

Thanks for reading! You rocks!
Thanks for reading! You rocks!

Mis à jour :