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.
