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.