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.
Don’t confused by the
thisinside the functiongetInstance, thatthisis the global objectwindow, so you are creating an object and assigned to the window object, and next time you call the constructor, you are checking whetherwindow.instanceis existing.The code
this.instance = null;is meanless, just confusing you. Remove it won’t change anything.The below is from the MDN.
Note the step3, when you have return statement in constructor, the returned result will be the result of the new expression.