Reputation: 87250
What is the simplest/cleanest way to implement the singleton pattern in JavaScript?
Upvotes: 487
Views: 388262
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
However we can fix no 2. easily:
const singletonishFactory = {
get notifier() {
return Object.defineProperty(
this, 'notifier', { value: new Notifier(), writable: false }
).notifier
},
};
Upvotes: 0
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
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
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
Reputation: 310
Simply use a class expression:
const singleton = new (class {
hello() { return 'world'; }
})();
console.log(singleton.hello()); //=> world
Upvotes: 0
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
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
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.
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
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
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
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
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
Reputation: 973
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
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
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
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
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:
But given the latest ECMA syntax, it is possible to get close with:
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);
DefaultField1
DefaultField2
Upvotes: 14
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
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
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
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
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
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.
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.
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
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
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
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
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
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; }
}();
var x1 = new X();
var x2 = new X();
console.log(x1 === x2)
Upvotes: 2
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