JavaScript Design Patterns: Singleton

If you’re paying attention, this is the fourth pattern I’m working on. It’s the last one on the list my manager gave me.

1 Singleton

Devan Patel: 4 JavaScript Design Patterns You Should Know

Using the Singleton pattern you can instantiate an object once, but create many instances of the same object using it. The example the article gives is of an office printer, being a shared resource where each employee has an instance of it on their machine, but it’s all the same instantiation. I almost understand the comparison.

var printer = (function () {

  // private

  var printerInstance;


  function create () {
    //private 
    function print() {
      // underlying printer mechanics
    }

    function turnOn() {
      // warm up
      // check for paper
    }

    // public

    return {
      // public + private states and behaviors
      print: print,
      turnOn: turnOn
    };
  }

  //public
  return {

    // if the printer instance doesn't exist, create it,
    // otherwise use the one that already exists.
    getInstance: function() {
      if(!printerInstance) {
        printerInstance = create();
      }
      return printerInstance;
    }
  };

  // say what?
  function Singleton () {
    if(!printerInstance) {
      printerInstance = intialize();
    }
  };

})();

var officePrinter = printer.getInstance();
var officePrinter2 = printer.getInstance();

I suppose this makes sense…I’m taking the assumption that the Singleton() is a bit of code the author forgot to remove. The author goes on to describe the real usefulness of this script being the creation of utilities, services, etc. – things that different parts of the code will need to use, and that state needs to be maintained. Time to mess around and see if I can understand this better.

var puppyMill = (function(){

  var puppyMillInstance;

  function create(){
    function makePuppy(){
      console.log("you just made a puppy")
    }

    return {
      makePuppy: makePuppy
    };
  }

  return {
    getInstance: function() {
      if(!puppyMillInstance){
        puppyMillInstance = create()
      }
      return puppyMillInstance;
    }
  };

})();

mill = puppyMill.getInstance();
mill.makePuppy();

We just made a puppy. More or less the same as the article’s code. This seems too simple to be enough. Which is why we’re now going to look at Rob Dodson’s article—if you recall from my most recent entry about the Observer Pattern, I couldn’t make it through his article on the same subject. And have been feeling like a real loser ever since.

2 Singleton, continued…

Rob Dodson: JavaScript Design Patterns: Singleton

“A Singleton is an object which can only be instantiated one time. Repeated calls to its constructor return the same instance and in this way one can ensure that they don’t accidentally create, say, two Users in a single User application.”

Sounds clear enough. Here’s the GoF definition:

Ensure a class only has one instance, and provide a global point of access to it.

2.1 Why Singletons are bad

Rob Dodson: JavaScript Design Patterns: Singleton

As I keep reading, we should hate that anything is ever in the global scope. And that’s precisely what the “global point of access” is in the GoF definition. The article points out that using Singletons can thereby make debugging a nightmare—and this may be one of those instances where n00bs like me make life hell by using patterns on everything.

2.2 Why Singletons are good

Rob Dodson: JavaScript Design Patterns: Singleton

The article then points out two popular uses for Singletons. The one that makes more sense to me is jQuery, where you load it up once and then refer to the same jQuery repeatedly by using $–that’s a Singleton. It’s in the global scope.

The other example is an object literal in the global scope, i.e.,

var dog = {
  name: "Spot",
  run: function(){
    console.log("I'm running!")
  }
}

The object has a single bit of memory reserved for it, and it’s referred to repeatedly. So what’s the big deal?

2.3 Namespacing

Rob Dodson: JavaScript Design Patterns: Singleton

The article suggests that the primary purpose of Singletons is to namespace our code, because JavaScript doesn’t have namespacing built in—we need to emulate it, and this is how we do it.

He now presents a scenario:

function jump(){
  // jumping stuff
}

function throwFireball(){
  // throw fireball
}

function fly(){
  // flying stuff
}

It’s a bunch of functions that we use frequently in our program. They:

  • “pollute the global namespace” because they have no parent other than window, the default global object
  • they could be overwritten easily—if someone wrote another throwFireball() for instance, without realizing we already had one.

The way to fix this is to create a namespace: a single global object that the rest of the code can use as a parent.

MARIO = {}

MARIO.jump = function(){
  // jumping stuff
}

MARIO.throwFireball = function(){
  // throw fireball
}

MARIO.fly = function(){
  // flying stuff
}

And now we’re safer, because we only have to worry about someone creating another MARIO object. And from here we can continue to nest things within it, including constructors or object literals.

MARIO = {}

MARIO.jump = function(){
  // jumping stuff
};

MARIO.throwFireball = function(){
  // throw fireball
};

MARIO.fly = function(){
  // flying stuff
};

MARIO.qualities = {
  color: "red",
}

// constructor function
MARIO.luigi = function(){
  this.color = "greenish";

  this.talk = function(){
    console.log("ciao");
  };
};

MARIO.luigi.prototype.danceAtTopOfVine = function(){
  // dance!
  console.log("i'm back on the vine, dancing.")
};

var luigi = new MARIO.luigi();
luigi.talk();
luigi.danceAtTopOfVine();
console.log(luigi.color);

2.4 But I like constructors

Rob Dodson: JavaScript Design Patterns: Singleton

Apparently that’s still all there is to it. Now the article presents some other ways of writing Singletons.

2.4.1 Singleton with a cached static property

Rob Dodson: JavaScript Design Patterns: Singleton

Here’s the code he writes:

function User() {  
    // do we have an existing instance?
    if (typeof User.instance === 'object') {
        return User.instance;
    }

    // proceed as normal
    this.firstName = 'John';
    this.lastName = 'Doe';

    // cache
    User.instance = this;

    // implicit return
    // return this;
}

Which I look at and have no idea what the point is. So I’ll step back and think about it—the point of the Singleton pattern is so that we create a single object that all instances refer back to. In this case, since it’s not an Object Literal we’re creating, it’s a constructor, we can create a new User by doing

a = new User ();

and each time we run this, it should create a new user, right? Well, that’d be the opposite of the Singleton goal, which I think would be to create one user instance that all users refer to. So in theory, if I create two instances of the User object, and change the name of one, it should change the name of the other one also—since by changing the name of one, I’m changing the single instance they’re both based on.

a = new User();
b = new User();
b.firstName = "Stephen"
console.log(a.firstName) // Object { firstName: "Stephen", lastName: "Doe" } 

So what is going on with the author’s script that makes this possible? First he’s checking to see if we have an existing instance of the object. And I think we could simplify this like so:

function User() {  
    // do we have an existing instance?
    if (User.instance) {
        return User.instance;
    }

    // proceed as normal
    this.firstName = 'John';
    this.lastName = 'Doe';

    // cache
    User.instance = this;

    // implicit return
    // return this;
}

a = new User();
b = new User();
b.firstName = "Stephen"
console.log(a)

If I understand correctly, though, User.instance = this; makes a clone of the User, which becomes the only one we have access to anymore. So the full process it goes through is like this:

a = new User();

do we have an existing User.instance? No. So continue through the code and set a.firstName to John, and a.lastName to Doe. And now make a copy of this object with the name John Doe and set it as a permanent part of the User constructor. What makes it permanent? Because the code will never reach the line setting it again. Why? Because…

b = new User();

do we have an existing User.instance? Yes. So return the User.instance we already have stored, and move back out of the function.

What I’m not sure about is how a is referring to User.instance–I don’t see how the implicit return of this is what returns to a–whereas with b it seems obvious. I should ask about this on StackOverflow.

http://stackoverflow.com/questions/41398632/how-does-the-javascript-singleton-pattern-with-cached-static-property-work

Lastly, here are some articles about the Singleton pattern. Mostly, it would seem that everyone agrees it just shouldn’t be used because it clutters up the global namespace.

http://geekswithblogs.net/AngelEyes/archive/2013/09/08/singleton-i-love-you-but-youre-bringing-me-down-re-uploaded.aspx

http://misko.hevery.com/2008/08/25/root-cause-of-singletons/

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s