Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@dmnsgn
Last active February 9, 2023 16:54
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save dmnsgn/4a6ad76de1b5928f13f68f406c70bb09 to your computer and use it in GitHub Desktop.
Save dmnsgn/4a6ad76de1b5928f13f68f406c70bb09 to your computer and use it in GitHub Desktop.
ES6 singleton pattern: module default exports an instance
class SingletonDefaultExportInstance {
constructor() {
this._type = 'SingletonDefaultExportInstance';
}
singletonMethod() {
return 'singletonMethod';
}
static staticMethod() {
return 'staticMethod';
}
get type() {
return this._type;
}
set type(value) {
this._type = value;
}
}
export default new SingletonDefaultExportInstance();
// ...
// index.js
import SingletonDefaultExportInstance from './SingletonDefaultExportInstance';
// Instantiate
// console.log(new SingletonDefaultExportInstance); // is not a constructor
// Prototype Method
console.log(SingletonDefaultExportInstance.type, SingletonDefaultExportInstance.singletonMethod());
// Getter/Setter
SingletonDefaultExportInstance.type = 'type updated';
console.log(SingletonDefaultExportInstance.type);
// Static method
console.log(SingletonDefaultExportInstance.constructor.staticMethod());
@bfintal
Copy link

bfintal commented Nov 5, 2017

As a named export:

export const singletonDefaultExportInstance = new SingletonDefaultExportInstance()

or if you want to export as the class' name:

const instance = new SingletonDefaultExportInstance()
export { instance as SingletonDefaultExportInstance }

@jasonkarns
Copy link

Be careful with this, because it's not a "true" singleton. It relies on the require cache for "singleton-ness", which isn't reliable.

For example, requiring the file above as require('./SingletonDefaultExportInstance') will result in a different instance of the module from require('./singletondefaultexportInstance') (assuming a case insensitive file-system).

@baltuonis
Copy link

@jasonkarns - so how do you export TRUE TRUE singleton?

@russelltrafford
Copy link

russelltrafford commented May 17, 2018

Yes, would be good to discuss :) Also for others coming across this later.

@sgnl
Copy link

sgnl commented Sep 27, 2018

IMHO, case insensitivity seems like it should be a bug with require's implementation if you're actually able to import a package that way.

@codewithcheese
Copy link

it also fails as a singleton if you have two copies of the package, for example in a mono repo where packages can have their own node_modules

@dmnsgn
Copy link
Author

dmnsgn commented Sep 26, 2020

This is part of a series on Singletons, if you are looking for different ways of implementing it: https://medium.com/@dmnsgn/singleton-pattern-in-es6-d2d021d150ae

@exodus4d
Copy link

@codewithcheese You could work around the issue and store instances even more "global" and use globalThis (works on Node and Browser)

// a.js
export class A {
    constructor(){
        console.log('A constructor()')
    }
    static get instance() {
        return (globalThis[Symbol.for(`PF_${A.name}`)] ||= new this());
    }
}

// index.js
import { A } from './a.js';

console.log('A.instance', A.instance);
console.log('A.instance', A.instance);

Or if you do not want to export A and just the single instance:

// a.js
class A { // <- no export here
    // same code
}

const {instance} = A; // destruct `static get instance` 
export {
    instance // ... and export instance. (optional re-naming if you do not want to import  something called "instance"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment