Hello,
Yesterday I wrote my first technical article ever! It is about singleton design pattern in JavaScript. I put it on Reddit and got some negative feedback about the pattern itself. This post is strictly informative, I don't say "use singletons" or "don't use singletons". I'm just saying "this is how you can implement it". It's up to you to decide whether you like it or not, whether is suits your application or solves your problems.
Also, as this is my first article ever created (not counting some stuff 10 years ago about jQuery click binding), I would really appreciate feedback, both about technical terms (I do not pose as an expert, I may be wrong in many places) and language.
Singleton in JavaScript
Singleton is one of the better-known patters in programming. While, by some, seen as an anti-pattern, it is worth knowing something about it.
Creating such class isn't really hard, but has some caveats. Firstly, its constructor has to return the instance. Secondly, such class cannot be extended nor modified by any ancestor. Generally speaking, extending will only link to the initial instance.
So, how to write a singleton class? First, we start like normal:
class SingletonClass {
constructor() {}
}
This is a standard class notation in ES2015 format. Please note the name and remember it. While creating anything, and especially a singleton class, choose the name wisely. Now I know that naming things is hard, but here we will be using the name rather that the this
.
Second step is to define the instance key within the class. Please note that this is static value, it refers to the class, not to the instance of the class.
class SingletonClass {
constructor() {
if (!!SingletonClass.instance) {
return SingletonClass.instance;
}
SingletonClass.instance = this;
return this;
}
}
Let's do some explaining. The constructor
starts with checking whether SingletonClass.instance
exists. Why not this
? Like I said earlier, we refer to the class. This is its static value, not related to an instance. If the condition is met, it means that the class has been already created sometime ago and that old instance can be returned instead creating new one.
Next we're assigning SingletonClass.instance
to this
, meaning, we are binding current instance to the class, coupling it.
Lastly, we return this
. This can be confusing, but look up. We've returned SingletonClass.instance
before. Without this return
, it would also work, but it's a good practice to keep consist return from a method.
Okay, this is all fine and well, but how can we prove that creating new instances is not possible? Well, good question. Let's enhance our class with something to do, for example, let it return the name we give it (yeah, programming!).
class SingletonClass {
constructor(name = "") {
if (!!SingletonClass.instance) {
return SingletonClass.instance;
}
SingletonClass.instance = this;
this.name = name;
return this;
}
getName() {
return this.name;
}
}
Let's create some instances now:
const instanceOne = new SingletonClass("One");
const instanceTwo = new SingletonClass("Two");
const instanceThree = new SingletonClass();
Okay, simple as that. So, now we can log it:
console.log(`Name of instanceOne is "${instanceOne.getName()}"`);
console.log(`Name of instanceTwo is "${instanceTwo.getName()}"`);
console.log(`Name of instanceThree is "${instanceThree.getName()}"`);
Can you guess, what those will log out?
Name of instanceOne is "One"
Name of instanceTwo is "One"
Name of instanceThree is "One"
Why is that? Because it's singleton class! It always uses the one instance that was created in the beginning. Try changing the order, move instanceThree
above instanceOne
. What are those console.log
s saying now?
Another thing is extending. This is a very popular feature of object-oriented programming. Popular, misused, abused etc. Singletons, technically, can't be extended, they don't have any ancestors. But, seeing is believing. Let's create a new class that will extend the old one:
class Extending extends SingletonClass {
shoutName() {
return this.name.toUpperCase();
}
}
So, normally Extending
should have two — getName
derived from SingletonClass
, and shoutName
, it's own. Let's see:
const A = new Extending();
console.log("getName" in A);
console.log("shoutName" in A);
What do you see in the console?
true
false
Why? Because the instance was created sometime ago, while we defined instanceOne
. The extension process can't even start, because SingletonClass
constructor
returns the instance first thing.
The only way to extend a singleton class is to do it before any instance is initiated. But this is an extreme anti-pattern, because you can't be sure that someone will not use the base class before you do the extending. Sure, you can extend it right after the declaration, but... why?
So, we now know how to create a class that has only one instance. Is it useful? If you want to use the benefits of a class but without allowing to use it freely. Sounds sarcastic, but isn't. Think of a logger. Why would you need to create multiple loggers? You should just use one, and it can be build using singleton. Think of caching database. You want all the data to be available without thinking of sharing the state somewhere.
The entire code is available at my CodePen, along with an additional check for multiple instances for the non-believers.
Top comments (32)
What is the advantage of using a class for a singleton versus let's say using an object literal?
This is a design pattern (object literal is also one, more specific to the JS). Difference is for example that literal can be extended.
In which way can you extend an object literal that you cannot extend your singleton object?
Sorry, I meant not extending but inherit. You can inherit from object literals by just creating new object based on your original one, like here. In singleton pattern, once you create the instance, it cannot be inherited in any way, because any ancestors will link to the original one.
Sorry again for confusion, lack of sleep has really got me this time :D
That's not what I would define as inheriting, you're cloning the object and adding extra properties to the clone. Nothing prevents anyone from cloning your singleton instance either, though, as long as they remember to carry on the prototype.
You are completely right, but here you are stepping away from the merit of the text, which is singleton design pattern. In JavaScript all (or are there some that aren't?) reference types can be cloned and those cloned modified.
Everyone should see it like that, I think it is even mentioned in antipattern book. The good thing is that most of its downsides can be avoided by allowing anyone to make an instance (making the constructor public) and have an interface (in the languages where they exists).
This way you can:
Making a singleton has its own problems, but the biggest issues arrive when you are using the instance directly, as a global static instance. This will create hard dependencies, spaghetti code, impossible to test and extend code.
In JS you can avoid these issues by making them as module dependencies, and keep the singleton instance inside a module, at init. But when required, you can inject a mock/stub/replacement in other modules. The best examples are the Window/Nodejs environments that are used as examples in the modules.
PS: is good to have one single instance of an entity (ex: configs, database connections and so on), but do not use them directly, send them as parameters to functions/modules (injection).
I haven't used singletons in a while, but I remember it being quite useful when I was building services for sensitive DOM manipulation and listening. You create a listener in a constructor and this guarantee that this is the only one available. But, like I said, this can be done in a myriad of other ways and I have written this strictly as an informative post.
Angular uses Singletons a lot. They provide a TypeScript decorator called:
@Injectable
which turns whichever class is decorated into a Singleton.The use-case in Angular is logic services. Sure you can use them to maintain state in your App but it can be messy, bug-prone and hairy if you do not take great care in doing so.
However, on the flip side, if you have a class whose function is to provide pure methods or to fetch data from a data-source, then why should you need multiple instances of this class.
In fact, having multiple instances will take up memory within your app. This could be dangerous!
If you do maintain state in your service, perhaps you want to know the
loggedInUser
, having a singleton for this makes perfect sense. You should only have one logged in user and therefore your singleton will only ever return this one user.If I may, I'd like to shamelessly plug my post about another valid usage of Singleton pattern 😛
The gist is that, Singleton pattern works great in combination with a Null pattern (where the null object is implemented as a singleton).
A valid usage of Singleton Pattern (with Null object Pattern)
Sung M. Kim ・ Jul 7 '18 ・ 2 min read
Thank you for the post Tomek.
I've never implemented singleton in JavaScript and found it interesting 🙂
Is there a way to prevent a singleton class to be
new
ed up in JavaScript?In C#, one can declare a constructor as private, constraining people to use
ClassName.instance
.Hi, and thanks foe your kind words!
JavaScript doesn't have private and public distinction (yet), so the short answer is - no.
The long one is - you can have private methods in TypeScript (and, private
constructor
). I've created a simple demo and – while TypeScript linter shouts that this is an error (noting thatconstructor
is indeed private), this gets compiled to JavaScript as a regular class that can have multiple instances. So I guess it's the compiler's job to fail here.Thanks Tomek for the follow-up~ 🙏
That sounds like another great reason to use TypeScript 🙂
Yes, TypeScript is a great tool and I use it recently for almost everything. The best thing is, it's JavaScript superset, so you don't really have to know everything and can just build your knowledge while working on a project. Create a plain JS code then slowly fill the type coverage as you go :)
Regardless singleton is right or not, there is a way to create a class, that can be extended and be a singleton for own type only.
Instead of using hard reference class constructor you should use constructor property of the instance.
this.constructor
is a reference to the direct constructor function.I'm not sure I understood you correctly, you mean using this I can create another class that will extend the
SingletonClass
? ThenSingletonClass
isn't a singleton, because, by definition, it cannot be extended.Plus, I have tried something like this and failed, can you provide the code?
I forgot about constructors prototype chain :P
Here you have working example:
This is not a singleton class now :) But nevertheless, excellent example.
Very nice!
Cool! Nice and simple explanation. Great job!
Thanks a lot :)
Keep up the good work!
Thanks for introducing me to this pattern. I've learned something here.
My application has a potentially very long list of materials, to be used anywhere within the ReactJS components hierarchy.
I want to load it only once, and to have it available everywhere.
For this purpose I'm writing an ES6 class to be instantiated as a singleton, sitting in global state with reactn.
This post clarified the way to code the singleton thimg, big time.
This may be the European way, with reasoning explanations instead of only code examples from where one is supposed to extract the gist of it.
Here it's clearly exposed.
Good!
Good job