Navigate / search

One Javascript Singleton to Rule Them All

I don’t want to get into a debate about Globals and Singletons right now. Suffice to say that I use Singletons on rare occasion and after creating one for a NodeJS project, I figured I’d save someone else the hassle. There are a bunch of answers on StackOverflow and one was very helpful…until I added 2 little words to the top of my constructor: “use strict”;  (I’ve updated the answer on StackOverflow to reflect the changes I’m going to explain here, and it’s awaiting peer review).

I’m something of a rebel so I chose not to use a getInstance() method.  I just don’t like the way it looks.  If I want a reference to the singleton I should just be able to type:

var singletonInstance = Singleton();
var singletonInstance = new Singleton();
//...or similar

I started with this solution and it worked really nicely for a while.

function MySingletonClass() {
  if ( arguments.callee._singletonInstance )
    return arguments.callee._singletonInstance;
  arguments.callee._singletonInstance = this;

  this._client = function() {
    // ...
  }
}

Unfortunately, I want to use the most up-to-date methodologies if I can and right now that’s strict mode in Javascript.  No problem, I just add “use strict”; at the top of my constructor and run my tests.  They all pass.  Great!  Then I ran the full build, which includes JSHint, and the results were not so pretty.  arguments.callee was deprecated in strict mode so I implemented the strict mode version of the answer on StackOverflow to get this:

var MySingletonClass = function() {
  "use strict";
  if ( MySingletonClass.prototype._singletonInstance ) {
    return MySingletonClass.prototype._singletonInstance;
  }

  MySingletonClass.prototype._singletonInstance = this;

  this._client = function() {
    // ...
  };
};

I fired up node and all hell broke loose. TypeError: Cannot set property ‘_client’ of undefined.  What!?!  All my tests are green.  JSHint is green.  There can’t possibly be anything wrong with my code.  I wish TDD meant that your code was perfect, but in fact it’s just for regression prevention.  I didn’t have a regression, I had a whole new problem.  If you instantiate a Javascript constructor in strict mode without the new operator “this” will be undefined.  I eventually ended up with the following test and solution:

test('should not throw if created without "new" operator', function() {
  (function() {
    var instance = require('./singleton');
  }).should.not.throw();
});
var MySingletonClass = function() {
  "use strict";
  if ( MySingletonClass.prototype._singletonInstance ) {
    return MySingletonClass.prototype._singletonInstance;
  }

  var self = this;

  if (typeof self === 'undefined') {
    self = new MySingletonClass();
  }

  MySingletonClass.prototype._singletonInstance = self;

  self._client = function() {
    // ...
  };
};

I hope that someone is saved the headaches that I was by using the above.  It’s literally copy, paste, change the singleton name, and you’re off and running.  Let me know if you have any comments/improvements.


If you enjoyed this post, please follow me on Twitter.