DEV Community

Cover image for Singleton Pattern in JavaScript
Artem
Artem

Posted on

Singleton Pattern in JavaScript

If you come from Java or C++ background, you are probably used to classic OOP model, and it is hard to imagine how you can implement singleton in JavaScript. The answer to this question is to use closures!

It is the same idea as module patterns, and comes from functional programming. The essence of closure, is creating an inner function in a scope of an outer function. If you know JS, you know that inner function has access to data members that are in the scope of the outer function. So, as long as you preserve a reference to the inner function, you can access enclosed members of the outer function, even when the outer function finished its execution. It may take some time to get your head around this definition!

Anyway, it is often easier to show something in code than explain in natural language!

Here is an example of singleton http client, which wraps an axios library:

let http = (function () {
  let axios = require('axios')

  return {
    get: function(url) {
      return axios.get(url)
    },
    post: function(url) {
      return axios.post(url)
    }
  }

}())
Enter fullscreen mode Exit fullscreen mode

As you can see we create an IIFE, holding instance of axios client in its scope. IIFE immediately resolves to a function containing get, and post methods. This way, we not only create a singleton instance of http, but also encapsulated axios from the rest of out program.

We still however, can access methods of axios instance using get and post functions, returned from closure:

http
  .get('https://baconipsum.com/api/?type=all-meat&paras=1&start-with-lorem=1')
  .then((res) => console.log(res.data))
Enter fullscreen mode Exit fullscreen mode

I know it is a lot of information for only few paragraphs of text. If you want to learn more about closures, or JS in general, I highly recommend watching FrontendMasters course by Douglas Crockford. It is free for all students, under GitHub Student Pack!

Top comments (11)

Collapse
 
andrewrothman profile image
Andrew Rothman • Edited

This can also be done in ES6 like so:

import axios from "axios";

class Http {
    static get(url) {
        return axios.get(url);
    }

    static post(url) {
        return axios.post(url);
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
hi_artem profile image
Artem

Yes, this is another way of doing it.

Collapse
 
mburszley profile image
Maximilian Burszley

Not sure this is a Singleton at all, just an immutable instance due to a closure creating pseudo-private members.

A Singleton indicates you can only ever have one instance of an object. Every new Http(args) would be a reference to the same thing.

Collapse
 
hi_artem profile image
Artem

This assumption is correct. That said, you should not use new keyword with this pattern. You can add a function to explicitly initialize singleton, and it would look more like traditional "Java" singleton. I don't think the latter is necessary though.

Collapse
 
sanderdebr profile image
sanderdebr

Good article! I reproduced it using ES6 modules:

Collapse
 
hi_artem profile image
Artem

Cool! Glad you like it, and thanks for ES6 example!

Collapse
 
adgower profile image
Alex Gower

Can you explain this to a 5 year old?

Collapse
 
hi_artem profile image
Artem

If the 5 year old already has some experience with programming, then it may work:
One way to implement singleton pattern in JS, is to encapsulate (enclose) desired members into outer function, but provide reference to desired properties of these members using inner function (same scope as the members). We can then immediately execute (invoke) inner function, and assign the value to a variable in a global scope (or different scope depending on use).

Collapse
 
adgower profile image
Alex Gower

Thank you,
From a 6 year old.

Collapse
 
halcika7 profile image
Haris Beslic

What about this approach?

class SomeClass {
constructor() {
if (!SomeClass.instance) {
SomeClass.instance = this;
}

return SomeClass.instance;

}
}

Collapse
 
hi_artem profile image
Artem

Yes, this is another way of doing it. More OOP way, I would say.