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)
}
}
}())
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¶s=1&start-with-lorem=1')
.then((res) => console.log(res.data))
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)
This can also be done in ES6 like so:
Yes, this is another way of doing it.
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.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.Good article! I reproduced it using ES6 modules:
Cool! Glad you like it, and thanks for ES6 example!
Can you explain this to a 5 year old?
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).
Thank you,
From a 6 year old.
What about this approach?
class SomeClass {
constructor() {
if (!SomeClass.instance) {
SomeClass.instance = this;
}
}
}
Yes, this is another way of doing it. More OOP way, I would say.