Simplest/cleanest way to implement a singleton in JavaScript
What is the simplest/cleanest way to implement the singleton pattern in JavaScript?
Solution 1:
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'
// ...
Solution 2:
I think the cleanest approach is something like:
var SingletonFactory = (function(){
function SingletonClass() {
//do stuff
}
var instance;
return {
getInstance: function(){
if (instance == null) {
instance = new SingletonClass();
// Hide the constructor so the returned object can't be new'd...
instance.constructor = null;
}
return instance;
}
};
})();
Afterwards, you can invoke the function as
var test = SingletonFactory.getInstance();
Solution 3:
I'm not sure I agree with the module pattern being used as a replacement for a singleton pattern. I've often seen singletons used and abused in places where they're wholly unnecessary, and I'm sure the module pattern fills many gaps where programmers would otherwise use a singleton. However, the module pattern is not a singleton.
Module pattern:
var foo = (function () {
"use strict";
function aPrivateFunction() {}
return { aPublicFunction: function () {...}, ... };
}());
Everything initialized in the module pattern happens when Foo
is declared. Additionally, the module pattern can be used to initialize a constructor, which could then be instantiated multiple times. While the module pattern is the right tool for many jobs, it's not equivalent to a singleton.
Singleton pattern:
short formvar Foo = function () {
"use strict";
if (Foo._instance) {
// This allows the constructor to be called multiple times
// and refer to the same instance. Another option is to
// throw an error.
return Foo._instance;
}
Foo._instance = this;
// Foo initialization code
};
Foo.getInstance = function () {
"use strict";
return Foo._instance || new Foo();
}
long form, using module patternvar Foo = (function () {
"use strict";
var instance; //prevent modification of "instance" variable
function Singleton() {
if (instance) {
return instance;
}
instance = this;
//Singleton initialization code
}
// Instance accessor
Singleton.getInstance = function () {
return instance || new Singleton();
}
return Singleton;
}());
In both versions of the singleton pattern that I've provided, the constructor itself can be used as the accessor:
var a,
b;
a = new Foo(); // Constructor initialization happens here
b = new Foo();
console.log(a === b); //true
If you don't feel comfortable using the constructor this way, you can throw an error in the if (instance)
statement, and stick to using the long form:
var a,
b;
a = Foo.getInstance(); // Constructor initialization happens here
b = Foo.getInstance();
console.log(a === b); // true
I should also mention that the singleton pattern fits well with the implicit constructor function pattern:
function Foo() {
if (Foo._instance) {
return Foo._instance;
}
// If the function wasn't called as a constructor,
// call it as a constructor and return the result
if (!(this instanceof Foo)) {
return new Foo();
}
Foo._instance = this;
}
var f = new Foo(); // Calls Foo as a constructor
-or-
var f = Foo(); // Also calls Foo as a constructor
Solution 4:
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"
Solution 5:
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