Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How/why does this JS singleton pattern work?

I came across this rather interesting way to create a JavaScript singleton that can be instantiated with the new keyword, like var x = new SingletonClass(). I have a pretty good grasp of variable scope and closures, etc., but I'm having a hard time understanding exactly why this block of code works the way it does.

// EDIT: DO NOT USE this code; see the answers below
function SingletonClass() {
  this.instance = null;
  var things = [];

  function getInstance() {
    if (!this.instance) {
      this.instance = {
        add: function(thing) {
          things.push(thing);
        },
        list: function() {
          console.log(things.toString());
        }
      };
    }
    return this.instance;
  }

  return getInstance();
}

var obj1 = new SingletonClass();
obj1.add("apple");
obj1.list();  //"apple"

var obj2 = new SingletonClass();
obj2.add("banana");
obj1.list();  //"apple,banana"
obj2.list();  //"apple,banana"

obj1.add("carrot");
obj1.list();  //"apple,banana,carrot"
obj2.list();  //"apple,banana,carrot"

My intuition says that each time a new SingletonClass is instantiated, this refers to that fresh new object -- but then since a totally separate object is returned by the constructor, I would figure this would just get discarded. But it hangs around. How? Why?

There's some tiny little detail going on here that I'm missing. Can anybody shine some light on it?

EDIT: Turns out this code is bad. The reason why it "magically" seems to hold a reference to the instance is because it's actually silently storing it in the global object. It's bad practice at best, and undoubtedly bug-prone.

like image 697
smitelli Avatar asked Oct 02 '12 02:10

smitelli


People also ask

How does the singleton pattern work?

Singleton pattern restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine. The singleton class must provide a global access point to get the instance of the class. Singleton pattern is used for logging, drivers objects, caching and thread pool.

What is singleton pattern in JS?

Singletons are used to create an instance of a class if it does not exist or else return the reference of the existing one. This means that singletons are created exactly once during the runtime of the application in the global scope. Based on this definition, singletons seem very similar to global variables.

What's a singleton function?

A singleton is a function or class which can have only one instance. It's a design pattern popularised by the “Gang of Four” in their influential Design Patterns. However, the singleton is one of several patterns in the book which have been criticised.

Why we are using singleton?

It is used where only a single instance of a class is required to control the action throughout the execution. A singleton class shouldn't have multiple instances in any case and at any cost. Singleton classes are used for logging, driver objects, caching and thread pool, database connections.


1 Answers

Don't confused by the this inside the function getInstance, that this is the global object window, so you are creating an object and assigned to the window object, and next time you call the constructor, you are checking whether window.instance is existing.

The code this.instance = null; is meanless, just confusing you. Remove it won't change anything.

The below is from the MDN.

When the code new foo(...) is executed, the following things happen:

  1. A new object is created, inheriting from foo.prototype.
  2. The constructor function foo is called with the specified arguments and this bound to the newly created object. new foo is equivalent to new foo(), i.e. if no argument list is specified, foo is called without arguments.
  3. The object returned by the constructor function becomes the result of the whole new expression. If the constructor function doesn't explicitly return an object, the object created in step 1 is used instead. (Normally constructors don't return a value, but they can choose to do so if they want to override the normal object creation process.)

Note the step3, when you have return statement in constructor, the returned result will be the result of the new expression.

like image 82
xdazz Avatar answered Sep 27 '22 20:09

xdazz