JavaScript Design Patterns: The Singleton

Samier Saeed
Samier Saeed
Share
In this article, we’ll dig into the best way to implement a singleton in JavaScript, looking at how this has evolved with the rise of ES6.
Among languages used in widespread production, JavaScript is by far the most quickly evolving, looking less like its earliest iterations and more like Python, with every new spec put forth by ECMA International. While the changes have their fair share of detractors, the new JavaScript does succeed in making code easier to read and reason about, easier to write in a way that adheres to software engineering best practices (particularly the concepts of modularity and SOLID principles), and easier to assemble into canonical software design patterns.

Explaining ES6

ES6 (aka ES2015) was the first major update to the language since ES5 was standardized in 2009. Almost all modern browsers support ES6. However, if you need to accommodate older browsers, ES6 code can easily be transpiled into ES5 using a tool such as Babel. ES6 gives JavaScript a ton of new features, including a superior syntax for classes, and new keywords for variable declarations. You can learn more about it by perusing SitePoint articles on the subject
.

What Is a Singleton

9 Puzzle pieces. 8 are gray, 1 is red. A visual representation of the singleton pattern In case you’re unfamiliar with the singleton pattern, it is, at its core, a design pattern that restricts the instantiation of a class to one object. Usually, the goal is to manage global application state. Some examples I’ve seen or written myself include using a singleton as the source of config settings for a web app, on the client side for anything initiated with an API key (you usually don’t want to risk sending multiple analytics tracking calls, for example), and to store data in memory in a client-side web application (e.g. stores in Flux). A singleton should be immutable by the consuming code, and there should be no danger of instantiating more than one of them. Note: there are scenarios when singletons might be bad, and arguments that they are, in fact, always bad. For that discussion, you can check out this helpful article on the subject.

The Old Way of Creating a Singleton in JavaScript

The old way of writing a singleton in JavaScript involves leveraging closures and immediately invoked function expressions . Here’s how we might write a (very simple) store for a hypothetical Flux implementation the old way:
var UserStore = (function(){
  var _data = [];

  function add(item){
    _data.push(item);
  }

  function get(id){
    return _data.find((d) => {
      return d.id === id;
    });
  }

  return {
    add: add,
    get: get
  };
}());
When that code is interpreted, UserStore will be set to the result of that immediately invoked function — an object that exposes two functions, but that does not grant direct access to the collection of data. However, this code is more verbose than it needs to be, and also doesn’t give us the immutability we desire when making use of singletons. Code executed later could modify either one of the exposed functions, or even redefine UserStore
altogether. Moreover, the modifying/offending code could be anywhere! If we got bugs as a result of unexpected modification of UsersStore, tracking them down in a larger project could prove very frustrating. There are more advanced moves you could pull to mitigate some of these downsides, as specified in this article by Ben Cherry. (His goal is to create modules, which just happen to be singletons, but the pattern is the same.) But those add unneeded complexity to the code, while still failing to get us exactly what we want.

The New Way(s)

By leveraging ES6 features, mainly modules and the new const variable declaration, we can write singletons in ways that are not only more concise, but which better meet our requirements. Let’s start with the most basic implementation. Here’s (a cleaner and more powerful) modern interpretation of the above example:
const _data = [];

const UserStore = {
  add: item => _data.push(item),
  get: id => _data.find(d => d.id === id)
}

Object.freeze(UserStore);
export default UserStore;
As you can see, this way offers an improvement in readability. But where it really shines is in the constraint imposed upon code that consumes our little singleton module here: the consuming code cannot reassign UserStore because of the const keyword. And as a result of our use of Object.freeze, its methods cannot be changed, nor can new methods or properties be added to it. Furthermore, because we’re taking advantage of ES6 modules, we know exactly where UserStore is used. Now, here we’ve made UserStore
an object literal. Most of the time, going with an object literal is the most readable and concise option. However, there are times when you might want to exploit the benefits of going with a traditional class. For example, stores in Flux will all have a lot of the same base functionality. Leveraging traditional object-oriented inheritance is one way to get that repetitive functionality while keeping your code DRY. Here’s how the implementation would look if we wanted to utilize ES6 classes:
class UserStore {
  constructor(){
    this._data = [];
  }

  add(item){
    this._data.push(item);
  }

  get(id){
    return this._data.find(d => d.id === id);
  }
}

const instance = new UserStore();
Object.freeze(instance);

export default instance;
This way is slightly more verbose than using an object literal, and our example is so simple that we don’t really see any benefits from using a class (though it will come in handy in the final example). One benefit to the class route that might not be obvious is that, if this is your front-end code, and your back end is written in C# or Java, you can employ a lot of the same design patterns in your client-side application as you do on the back end, and increase your team’s efficiency (if you’re small and people are working full-stack). Sounds soft and hard to measure, but I’ve experienced it firsthand working on a C# application with a React front end, and the benefit is real. It should be noted that, technically, the immutability and non-overridability of the singleton using both of these patterns can be subverted by the motivated provocateur. An object literal can be copied, even if it itself is const, by using Object.assign. And when we export an instance of a class, though we aren’t directly exposing the class itself to the consuming code, the constructor of any instance is available in JavaScript and can be invoked to create new instances. Obviously, though, that all takes at least a little bit of effort, and hopefully your fellow devs aren’t so insistent on violating the singleton pattern. But let’s say you wanted to be extra sure that nobody messed with the singleness of your singleton, and you also wanted it to match the implementation of singletons in the object-oriented world even more closely. Here’s something you could do:
class UserStore {
  constructor(){
   if(! UserStore.instance){
     this._data = [];
     UserStore.instance = this;
   }

   return UserStore.instance;
  }

 //rest is the same code as preceding example

}

const instance = new UserStore();
Object.freeze(instance);

export default instance;
By adding the extra step of holding a reference to the instance, we can check whether or not we’ve already instantiated a UserStore
, and if we have, we won’t create a new one. As you can see, this also makes good use of the fact that we’ve made UserStore a class.

Thoughts? Hate Mail?

There are no doubt plenty of developers who have been using the old singleton/module pattern in JavaScript for a number of years, and who find it works quite well for them. Nevertheless, because finding better ways to do things is so central to the ethos of being a developer, hopefully we see cleaner and easier-to-reason-about patterns like this one gaining more and more traction. Especially once it becomes easier and more commonplace to utilize ES6+ features. This is a pattern I’ve employed in production to build the stores in a custom Flux implementation (stores which had a little more going on than our examples here), and it worked well. But if you can see holes in it, please let me know. Also please advocate for whichever of the new patterns you prefer, and whether or not you think object literals are the way to go, or if you prefer classes!

Frequently Asked Questions (FAQs) about JavaScript Singleton Design Pattern

What is the Singleton Design Pattern in JavaScript?

The Singleton Design Pattern in JavaScript is a design pattern that restricts the instantiation of a class to a single instance. This means that no matter how many times you try to create a new instance of the class, you will always get the same instance. This pattern is useful when exactly one object is needed to coordinate actions across the system. For example, if you have a logging system in your application, you might want to have only one instance of the logger to avoid inconsistencies in the log.

How do I implement a Singleton in JavaScript?

Implementing a Singleton in JavaScript is quite straightforward. You can create a Singleton by using an immediately invoked function expression (IIFE) that returns an object. This object is the Singleton instance. Here is a simple example:

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;
}
};
})();

In this example, the getInstance method checks if an instance of the Singleton already exists. If it does, it returns that instance. If it doesn’t, it creates a new instance and returns it.

What are the advantages of using a Singleton in JavaScript?

The Singleton pattern has several advantages. First, it ensures that there is only one instance of a class, which can be useful for coordinating actions across a system. Second, it provides a global point of access to that instance, which can be useful for sharing resources or communicating between different parts of an application. Finally, it can help to reduce the memory footprint of your application, as you only need to create one instance of a class.

Are there any disadvantages to using a Singleton in JavaScript?

While the Singleton pattern can be useful, it also has some disadvantages. One of the main disadvantages is that it can make your code harder to test, as it introduces a global state into your application. This can make it difficult to isolate tests, as they can potentially affect each other through the shared Singleton instance. Additionally, the use of a Singleton can lead to tight coupling between classes, which can make your code less flexible and harder to maintain.

Can I create a Singleton with ES6 classes in JavaScript?

Yes, you can create a Singleton with ES6 classes in JavaScript. Here is an example:

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

In this example, the constructor checks if an instance of the Singleton already exists. If it does, it returns that instance. If it doesn’t, it creates a new instance and returns it.

How can I use a Singleton in a real-world application?

Singletons can be used in a variety of real-world applications. For example, you might use a Singleton for a logging system, where you want to ensure that there is only one logger instance in your application. You might also use a Singleton for a configuration manager, where you want to provide a global point of access to configuration settings.

Can I have multiple Singletons in a JavaScript application?

Yes, you can have multiple Singletons in a JavaScript application. Each Singleton would be responsible for a different part of the application. However, it’s important to be careful when using multiple Singletons, as they can potentially introduce a lot of global state into your application, which can make your code harder to test and maintain.

How can I test a Singleton in JavaScript?

Testing a Singleton in JavaScript can be challenging, as it introduces a global state into your application. One approach is to create a method in your Singleton that allows you to reset the instance for testing purposes. This can allow you to isolate your tests, so they don’t affect each other through the shared Singleton instance.

Can I use a Singleton in a multi-threaded environment?

JavaScript is single-threaded, so you don’t need to worry about thread safety when using a Singleton in JavaScript. However, if you were using a Singleton in a multi-threaded environment, you would need to ensure that the Singleton instance is thread-safe.

Are there any alternatives to the Singleton pattern in JavaScript?

Yes, there are several alternatives to the Singleton pattern in JavaScript. One alternative is the Module pattern, which allows you to encapsulate private and public members within a single object. Another alternative is the Factory pattern, which provides a way to create objects without specifying the exact class of object that will be created.