Jakub Arnold
Jakub Arnold

Reputation: 87250

Simplest/cleanest way to implement a singleton in JavaScript

What is the simplest/cleanest way to implement the singleton pattern in JavaScript?

Upvotes: 487

Views: 388262

Answers (30)

Philzen
Philzen

Reputation: 4667

I came here looking thinking i was looking for a singleton, with the XY-Problem of actually looking for an object-holder that provides lazy initialization.

For this, a self-overwriting getter as found on MDN may be just what you want:

const singletonishFactory = {
  get notifier() {
    delete this.notifier;
    return this.notifier = new Notifier();
  },
};

This pattern has the nice advantage of saving the comparison whether the object has been instantiated on 2nd, 3rd, etc. access and thus is more performant (and much shorter) than implementing a "classical singleton" pattern in javascript:

Object.getOwnPropertyDescriptor(singletonishFactory, 'notifier')
// → Object { get: notifier(), set: undefined, enumerable: true, configurable: true }

const notifierInstance = singletonishFactory.notifier // (getter is called and replaced)

Object.getOwnPropertyDescriptor(singletonishFactory, 'notifier')
// → Object { value: Notifier, writable: true, enumerable: true, configurable: true }

const notifierInstance2 = singletonishFactory.notifier // (directly accesses instance pointer)

Object.is(notifierInstance, notifierInstance2) // → TRUE

Functionally, it behaves almost exact like a singleton, with the exception that

  1. it doesn't instantiate itself – which is why this pattern is more like a factory
  2. value could be still overwritten

However we can fix no 2. easily:

const singletonishFactory = {
  get notifier() {
    return Object.defineProperty(
      this, 'notifier', { value: new Notifier(), writable: false }
    ).notifier
  },
};

Upvotes: 0

Christian C. Salvadó
Christian C. Salvadó

Reputation: 827862

I think the easiest way is to declare a simple object literal:

var myInstance = {
  method1: function () {
    // ...
  },
  method2: function () {
    // ...
  }
};

If you want private members on your singleton instance, you can do something like this:

var myInstance = (function() {
  var privateVar = '';

  function privateMethod () {
    // ...
  }

  return { // public interface
    publicMethod1: function () {
      // All private members are accessible here
    },
    publicMethod2: function () {
    }
  };
})();

This has been called the module pattern, and it basically allows you to encapsulate private members on an object, by taking advantage of the use of closures.

If you want to prevent the modification of the singleton object, you can freeze it, using the ES5 Object.freeze method.

That will make the object immutable, preventing any modification to the its structure and values.

If you are using ES6, you can represent a singleton using ES Modules very easily, and you can even hold private state by declaring variables at the module scope:

// my-singleton.js
const somePrivateState = []

function privateFn () {
  // ...
}

export default {
  method1() {
    // ...
  },
  method2() {
    // ...
  }
}

Then you can simply import the singleton object to use it:

import myInstance from './my-singleton.js'
// ...

Upvotes: 409

whmkr
whmkr

Reputation: 3085

Since most new js code is being written in modules, this simple pattern seems to be missing from the answers.

let instance = null

function makeThing() {
  // make and return thing
}

export getThing() {
  if (!instance) {
    instance = makeThing()
  }
  
  return instance
}

Upvotes: 0

Aravinda Meewalaarachchi
Aravinda Meewalaarachchi

Reputation: 2639

This is how I implement singleton pattern using ES6 features. Yes, I know this does not look like an Object-oriented approach, but I find this method is easy to implement and a clean way to implement.

const Singleton = (() => {
  var _instance = !_instance && new Object('Object created....');
  return () => _instance;
})();

//************************************************************************

var instance1 = Singleton();
var instance2 = Singleton();
console.log(instance1 === instance2); // true

Upvotes: 5

mynyml
mynyml

Reputation: 310

Simply use a class expression:

const singleton = new (class {
    hello() { return 'world'; }
})();

console.log(singleton.hello()); //=> world

Upvotes: 0

user3492648
user3492648

Reputation: 53

This knowledge is base from I am learning Java, though Java and Javascript is different, the concept of Singleton and how Java do it is just the same. In my opinion, The class style from JS is clean by itself rather than var initialization.

class Singleton {
    // use hashtag which entails that the variable can only be accessed from self scope
    static #instance = null;
    static getInstance() {
        if (this.#instance === null) this.#instance = new Singleton();
        return this.#instance;
    }

    // some class property
    hello = 'world';

    // or initialize the variable in the constructor, depend on your preference
    constructor() {
        // this.hello = 'world';
    }

    /* you can also add parameters on the constructor & getInstance
     * e.g. 
     * static getInstance(param1, param2) {...new Singleton(param1, param2)}
     * constructor(param1, param2) {...}
     */

}




// this is the same code for java and normal way for singleton for class
// just use static so you can get instance


// testing the singleton
var s1,s2;
s1 = Singleton.getInstance();
s2 = Singleton.getInstance();

// you cannot access the property, immediately
if (Singleton.hello === undefined) console.log('getInstance so you can access this');

console.log(s1.hello);
// result: "world"

console.log(s2.hello);
// result: "world"


// set the value of Singleton object
s2.hello = "hi";
    console.log(s1.hello);
    // result: "hi"

    console.log(s2.hello);
    // result: "hi"
// this is just an evidence which means that they are the same even in property level

if (s1 === s2) console.log("S1 & S2 is the same object");
// result: "S1 & S2 is the same object"

// don't use something like `var s1 = new Singleton();`
// this will defeat your purpose of just (1 object), one instance of class

Upvotes: 2

James
James

Reputation: 348

Using ES6 classes and private static fields. Invoking new instances of the Singleton class will return the same instance. The instance variable is also private and can't be accessed outside the class.

class Singleton {
  // # is a new Javascript feature that denotes private
  static #instance;

  constructor() {
    if (!Singleton.#instance) {
      Singleton.#instance = this
    } 
    return Singleton.#instance
  }

  get() {
    return Singleton.#instance;
  }
}

const a = new Singleton();
const b = new Singleton();
console.log(a.get() === b.get()) // true
console.log(Singleton.instance === undefined) // true

Upvotes: 11

vrspiration
vrspiration

Reputation: 97

So to be fair the simplest answer is usually the best. An object literal is always a single instance. Not much reason for anything more complex other than, perhaps allocation of memory on demand.

That being said, here is a classical implementation of a singleton using ES6.

  • The instance "field" is "private". This really means we hide the instance as a property of the constructor. Somewhere not Constructor.prototype, which will be available to the instance through prototipical inheritance.
  • The constructor is "private". We really are just throwing an error when the caller is not the static getInstance method.

Also of note. It’s important to understand what the keyword this means in different contexts.

In the constructor, this points to the instance created.

In the static getInstance method, this points to the left of the dot, Universe constructor function which, is an object like most things in JS and can hold properties.

class Universe {
    constructor() {
       if (!((new Error).stack.indexOf("getInstance") > -1)) {
           throw new Error("Constructor is private. Use static method getInstance.");  
       } 
       this.constructor.instance = this;
       this.size = 1;
    }
    static getInstance() {
        if (this.instance) {
            return this.instance;
        }
        return new this;
    }
    expand() {
        this.size *= 2;
        return this.size;
    }
}


console.log(Universe.getInstance())
console.log(Universe.getInstance().expand())
console.log(Universe.getInstance())
console.log(new Universe())

Upvotes: -1

Marek Lisiecki
Marek Lisiecki

Reputation: 726

class Singelton {
    static #instance;

    #testValue;

    constructor() {
        if (Singelton.#instance instanceof Singelton) {
            return Singelton.#instance;
        }

        Singelton.#instance = this;
        return Singelton.#instance;
    }

    get testValue() {
        return this.#testValue;
    }

    set testValue(value) {
        this.#testValue = value;
    }
}

test:

let x = new Singelton();
x.testValue = 123;

let y = new Singelton();

console.log({isSingelton: x === y, testValueFromY: y.testValue});

Upvotes: 3

iaforek
iaforek

Reputation: 3108

If you're using node.JS then you can take advantage of node.JS caching mechanism and your Singleton will be as simple as:

class Singleton {
    constructor() {
        this.message = 'I am an instance';
    }
}
module.exports = new Singleton();

Please note that we export not the class Singleton but instance Singleton().

Node.JS will cache and reuse the same object each time it’s required.

For more details please check: Node.JS and Singleton Pattern

Upvotes: 33

Wu_
Wu_

Reputation: 145

let MySingleton = (function () {
  var _instance
  function init() {
    if(!_instance) {
      _instance = { $knew: 1 }
    }
    return _instance
  }
  let publicAPIs = {
    getInstance: function() {
      return init()
    }
  }
  // this prevents customize the MySingleton, like MySingleton.x = 1
  Object.freeze(publicAPIs) 
  // this prevents customize the MySingleton.getInstance(), like MySingleton.getInstance().x = 1
  Object.freeze(publicAPIs.getInstance())
  return publicAPIs
})();

Upvotes: 2

The Seeker
The Seeker

Reputation: 632

var singleton = (function () {

    var singleton = function(){
        // Do stuff
    }
    var instance = new singleton();
    return function(){
        return instance;
    }
})();

A solution without the getInstance method.

Upvotes: -3

aswininayak
aswininayak

Reputation: 973

Simple Example

class Settings {

  constructor() {
    if (Settings.instance instanceof Settings) {
      return Settings.instance;
    }
    this.settings = {
      id: Math.floor(Math.random() * 4000),
      name: "background",
    };
    Object.freeze(this.settings);
    Object.freeze(this);
    Settings.instance = this;
  }

}

var o1 = new Settings();
var o2 = new Settings();

console.dir(o1);
console.dir(o2);

if (o1 === o2) {
  console.log("Matched");
}

Upvotes: 1

Supradeep
Supradeep

Reputation: 161

If you want to use classes:

class Singleton {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    if(this.constructor.instance)
      return this.constructor.instance;
    this.constructor.instance = this;
  }
}
let x = new Singleton('s', 1);
let y = new Singleton('k', 2);

Output for the above will be:

console.log(x.name, x.age, y.name, y.age) // s 1 s 1

Another way of writing Singleton using function

function AnotherSingleton (name,age) {
  this.name = name;
  this.age = age;
  if(this.constructor.instance)
    return this.constructor.instance;
  this.constructor.instance = this;
}

let a = new AnotherSingleton('s', 1);
let b = new AnotherSingleton('k', 2);

Output for the above will be:

console.log(a.name, a.age, b.name, b.age) // s 1 s 1

Upvotes: 12

UtkarshPramodGupta
UtkarshPramodGupta

Reputation: 8162

In ES6 the right way to do this is:

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

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

var instanceOne = new MyClass() // Executes succesfully
var instanceTwo = new MyClass() // Throws error

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

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

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

var instanceOne = new MyClass()
var instanceTwo = new MyClass()

console.log(instanceOne === instanceTwo) // Logs "true"

Upvotes: 150

Gin Quin
Gin Quin

Reputation: 1113

For me the cleanest way to do so is:

const singleton = new class {
    name = "foo"
    constructor() {
        console.log(`Singleton ${this.name} constructed`)
    }
}

With this syntax you are certain your singleton is and will remain unique. You can also enjoy the sugarness of class syntax and use this as expected.

(Note that class fields require node v12+ or a modern browser.)

Upvotes: 4

Wolfgang Fahl
Wolfgang Fahl

Reputation: 15594

The simplest/cleanest for me means also simply to understand and no bells & whistles as are much discussed in the Java version of the discussion:

What is an efficient way to implement a singleton pattern in Java?

The answer that would fit simplest/cleanest best there from my point of view is:

Jonathan's answer to What is an efficient way to implement a singleton pattern in Java?

And it can only partly be translated to JavaScript. Some of the difference in JavaScript are:

  • constructors can't be private
  • Classes can't have declared fields

But given the latest ECMA syntax, it is possible to get close with:

Singleton pattern as a JavaScript class example

 class Singleton {

  constructor(field1,field2) {
    this.field1=field1;
    this.field2=field2;
    Singleton.instance=this;
  }

  static getInstance() {
    if (!Singleton.instance) {
      Singleton.instance=new Singleton('DefaultField1','DefaultField2');
    }
    return Singleton.instance;
  }
}

Example Usage

console.log(Singleton.getInstance().field1);
console.log(Singleton.getInstance().field2);

Example Result

DefaultField1
DefaultField2

Upvotes: 14

Mark
Mark

Reputation: 9428

I've found the following to be the easiest singleton pattern, because using the new operator makes this immediately available within the function, eliminating the need to return an object literal:

var singleton = new (function () {

  var private = "A private value";

  this.printSomething = function() {
      console.log(private);
  }
})();

singleton.printSomething();

Upvotes: 3

Daniel
Daniel

Reputation: 365

The following works in Node.js version 6:

class Foo {
  constructor(msg) {

    if (Foo.singleton) {
      return Foo.singleton;
    }

    this.msg = msg;
    Foo.singleton = this;
    return Foo.singleton;
  }
}

We test:

const f = new Foo('blah');
const d = new Foo('nope');
console.log(f); // => Foo { msg: 'blah' }
console.log(d); // => Foo { msg: 'blah' }

Upvotes: 19

令狐葱
令狐葱

Reputation: 1127

The clearest answer should be this one from the book Learning JavaScript Design Patterns by Addy Osmani.

var mySingleton = (function () {

  // Instance stores a reference to the singleton
  var instance;

  function init() {

    // Singleton

    // Private methods and variables
    function privateMethod(){
        console.log( "I am private" );
    }

    var privateVariable = "I'm also private";

    var privateRandomNumber = Math.random();

    return {

      // Public methods and variables
      publicMethod: function () {
        console.log( "The public can see me!" );
      },

      publicProperty: "I am also public",

      getRandomNumber: function() {
        return privateRandomNumber;
      }

    };

  };

  return {

    // Get the singleton instance if one exists
    // or create one if it doesn't
    getInstance: function () {

      if ( !instance ) {
        instance = init();
      }

      return instance;
    }

  };

})();

Upvotes: 5

Sheo Dayal Singh
Sheo Dayal Singh

Reputation: 1683

Here is a simple example to explain the singleton pattern in JavaScript.

var Singleton = (function() {
    var instance;
    var init = function() {
        return {
            display:function() {
                alert("This is a singleton pattern demo");
            }
        };
    };
    return {
        getInstance:function(){
            if(!instance){
                alert("Singleton check");
                instance = init();
            }
            return instance;
        }
    };
})();

// In this call first display alert("Singleton check")
// and then alert("This is a singleton pattern demo");
// It means one object is created

var inst = Singleton.getInstance();
inst.display();

// In this call only display alert("This is a singleton pattern demo")
// it means second time new object is not created,
// it uses the already created object

var inst1 = Singleton.getInstance();
inst1.display();

Upvotes: 2

Xaqron
Xaqron

Reputation: 30867

In ECMAScript 2015 (ES6):

class Singleton {
  constructor () {
    if (!Singleton.instance) {
      Singleton.instance = this
    }
    // Initialize object
    return Singleton.instance
  }
  // Properties & Methods
}

const instance = new Singleton()
Object.freeze(instance)

export default instance

Upvotes: 39

Alt Eisen
Alt Eisen

Reputation: 648

I believe this is the simplest/cleanest and most intuitive way though it requires ECMAScript 2016 (ES7):

export default class Singleton {

  static instance;

  constructor(){
    if(instance){
      return instance;
    }

    this.state = "duke";
    this.instance = this;
  }

}

The source code is from: adam-bien.com

Upvotes: 4

Mohideen bin Mohammed
Mohideen bin Mohammed

Reputation: 20196

Singleton:

Ensure a class has only one instance and provides a global point of access to it.

The singleton pattern limits the number of instances of a particular object to just one. This single instance is called the singleton.

  • defines getInstance() which returns the unique instance.
  • responsible for creating and managing the instance object.

The singleton object is implemented as an immediate anonymous function. The function executes immediately by wrapping it in brackets followed by two additional brackets. It is called anonymous because it doesn't have a name.

Sample Program

var Singleton = (function () {
    var instance;

    function createInstance() {
        var object = new Object("I am the instance");
        return object;
    }

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

function run() {

    var instance1 = Singleton.getInstance();
    var instance2 = Singleton.getInstance();

    alert("Same instance? " + (instance1 === instance2));
}

run()

Upvotes: 2

user2756335
user2756335

Reputation: 149

A singleton in JavaScript is achieved using the module pattern and closures.

Below is the code which is pretty much self-explanatory -

// Singleton example.
var singleton = (function() {
  var instance;

  function init() {
    var privateVar1 = "this is a private variable";
    var privateVar2 = "another var";

    function pubMethod() {
      // Accessing private variables from inside.
      console.log(this.privateVar1);
      console.log(this.privateVar2);
      console.log("inside of a public method");
    };
  }

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

  return {
    getInstance: getInstance
  }
})();

var obj1 = singleton.getInstance();
var obj2 = singleton.getInstance();

console.log(obj1 === obj2); // Check for type and value.

Upvotes: -1

Siddhartha
Siddhartha

Reputation: 29

The main key is to understand the closure's importance behind this. So a property even inside the inner function will be private with the help of the closure.

var Singleton = function () {
    var instance;

    function init() {

       function privateMethod() {
           console.log("private via closure");
       }

       var privateVariable = "Private Property";

       var privateRandomNumber = Math.random(); // This is also private

       return {
           getRandomNumber: function () {  // Access via getter in init call
               return privateRandomNumber;
           }
       };
    };

    return {
        getInstance: function () {

            if (!instance) {
                instance = init();
            }
            return instance;
        }
    };
};

Upvotes: 0

Vad
Vad

Reputation: 4099

You can do it with decorators like in this example below for TypeScript:

class YourClass {

    @Singleton static singleton() {}

}

function Singleton(target, name, descriptor) {
    var instance;
    descriptor.value = () => {
        if(!instance) instance = new target;
        return instance;
    };
}

Then you use your singleton like this:

var myInstance = YourClass.singleton();

As of this writing, decorators are not readily available in JavaScript engines. You would need to make sure your JavaScript runtime has decorators actually enabled or use compilers like Babel and TypeScript.

Also note that the singleton instance is created "lazy", i.e., it is created only when you use it for the first time.

Upvotes: 1

serv-inc
serv-inc

Reputation: 38267

You did not say "in the browser". Otherwise, you can use Node.js modules. These are the same for each require call. Basic example:

The contents of foo.js:

const circle = require('./circle.js');
console.log(`The area of a circle of radius 4 is ${circle.area(4)}`);

The contents of circle.js:

const PI = Math.PI;

exports.area = (r) => PI * r * r;

exports.circumference = (r) => 2 * PI * r;

Note that you cannot access circle.PI, as it is not exported.

While this does not work in the browser, it is simple and clean.

Upvotes: 0

Olencha
Olencha

Reputation: 418

My two cents: I have a constructor function (CF), for example,

var A = function(arg1){
  this.arg1 = arg1
};

I need just every object created by this CF to be the same.

var X = function(){
  var instance = {};
  return function(){ return instance; }
}();

Test

var x1 = new X();
var x2 = new X();
console.log(x1 === x2)

Upvotes: 2

Nawal
Nawal

Reputation: 381

This is also a singleton:

function Singleton() {
    var i = 0;
    var self = this;

    this.doStuff = function () {
        i = i + 1;
        console.log('do stuff', i);
    };

    Singleton = function () { return self };
    return this;
}

s = Singleton();
s.doStuff();

Upvotes: 1

Related Questions