6

After reading a lot of articles on singleton pattern, and making some tests, I found no difference between the singleton pattern like this (http://jsfiddle.net/bhsQC/1/):

var TheObject = function () {
    var instance;

    function init() {
        var that = this;
        var foo = 1;

        function consoleIt() {
            console.log(that, foo);
        }
        return {
            bar: function () {
                consoleIt()
            }
        };
    }
    return {
        getInstance: function () {
            if (!instance) {
                instance = init();
            }
            return instance;
        }
    };
}();
var myObject = TheObject.getInstance();
myObject.bar();

and code like this (http://jsfiddle.net/9Qa9H/3/):

var myObject = function () {
    var that = this;
    var foo = 1;

    function consoleIt() {
        console.log(that, foo);
    }
    return {
        bar: function () {
            consoleIt();
        }
    };
}();
myObject.bar();

They both make only one instance of the object, they both can have "private" members, that points to window object in either of them. It's just that the latter one is simpler. Please, correct me if I'm wrong.

Using standard constructor like this (http://jsfiddle.net/vnpR7/2/):

var TheObject = function () {
    var that = this;
    var foo = 1;

    function consoleIt() {
        console.log(that, foo);
    }
    return {
        bar: function () {
            consoleIt();
        }
    };
};
var myObject = new TheObject();
myObject.bar();

has the advantage of correct usage of that, but isn't a singleton.

My question is: what are the overall advantages and disadvantages of these three approaches? (If it matters, I'm working on a web app using Dojo 1.9, so either way, this object will be inside Dojo's require).

Zemljoradnik
  • 2,672
  • 2
  • 18
  • 24
  • 1
    Just out of the curiosity why would someone use the singleton pattern in JavaScript? Wouldn't it make sense to use one object like: var obj1 = { } Sorry for offtopic – Kirill Ivlev May 21 '13 at 11:05
  • @KirillIvlev with singleton/module pattern you can have private vars and functions inside the IIFE. The singleton from OP seems to apply lazy loading as well - only instantiate when first called. – Fabrício Matté May 21 '13 at 11:05
  • I'd rather simply use an auto-invoking function to hide away the constructor, i.e., something like this: http://jsfiddle.net/qFMcL/ – Niko May 21 '13 at 12:32
  • I don't really understand why you want `that` point to `window`? – Bergi May 21 '13 at 13:05
  • Please see this answer by CMS: http://stackoverflow.com/a/1479341/113083 – hegemon May 21 '13 at 13:10
  • @Bergi I don't. It's a disadvantage of the singleton pattern. – Zemljoradnik May 21 '13 at 13:41
  • @hegemon Read it before I posted, but still wasn't sure. – Zemljoradnik May 21 '13 at 13:43
  • @Zemljoradnik: Now, it's not a disadvantage of the pattern if you're using the `this` keyword wrong… You can use it in "methods", but it does not make any sense in the module IEFE. – Bergi May 21 '13 at 15:49
  • @Bergi I don't get it... Why do you think it wouldn't make sense to use `this` in methods of IIFE? It isn't possible, but it would be helpful. Or am I missing something? – Zemljoradnik May 22 '13 at 07:22
  • @Zemljoradnik: It does make sense in the *methods* (like `bar` in your examples), but not in the module IEFE. What would be helpful? To let it point to the returned object? For that, you would need to assign it to a variable (`var that = {bar:…}; return bar;`) – Bergi May 22 '13 at 12:06

3 Answers3

3

Well, the real difference is the time of construction of the singleton. The second approach creates the singleton right away, the first only after being called the first time. Depending on what the singleton needs in memory, this might make a difference for your application. For example, you might need the singleton only if a user performs a certain action. So if the user does not do it, then it would be nice not to have to initialise the singleton at all.

Also, if the initialisation of the singleton is computationally intense, it is a good thing to be able to defer that until you really need the singleton.

Edit: And as Jani said, the last one isn't a singleton, so i didn't discuss it.

ghost23
  • 2,150
  • 1
  • 20
  • 35
  • Well yes, I missed the obvious - time of construction. In my case it doesn't matter, cause I'm using this sort of as a namespace. That's why I included the third option, because I'm still not sure should I be using singleton at all... – Zemljoradnik May 21 '13 at 14:01
  • All righty then, i don't see any other significant differences. Regarding wether you should be using a singleton at all, that of course, is a whole other dicussion :) – ghost23 May 21 '13 at 14:13
1

I don't think there's really a big practical difference between the first two.

The first one with getInstance behaves more like a singleton pattern in classical OOP languages like Java.

The second approach behaves more like a static class in classical OOP languages.

Obviously the issues both of these have are the same all singletons have (plenty of material for this if you look it up on google).

The last approach is not really even using new - you're returning an object from the "constructor". Obviously this one is not a singleton at all, and as such, would be the preferred approach.

Jani Hartikainen
  • 42,745
  • 10
  • 68
  • 86
  • I'm prepared to be downvoted for this question, but - what are the "issues" of singletons, apart from the `that` problem? There are lots of questions out there, but I just can't find any good answers. – Zemljoradnik May 21 '13 at 14:18
  • 1
    Here's some good answers on SO regarding that http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons – Jani Hartikainen May 21 '13 at 15:13
0

I like to build singletons likes this:

function FriendHandler(){ 
    if(FriendHandler.prototype.singleton){ 
        return FriendHandler.prototype.singleton; 
    }

    if(!(this instanceOf FriendHandler)){
        return new FriendHandler();
    }

    FriendHandler.prototype.singleton = this;
 ...
    this.selectFriends = function(firstName){
        ...
    };
}

If you do:

new FriendHandler()
or
FriendHandler()

It always returns the same instance.

I wrote about it some months ago: http://franciscomsferreira.blogspot.com/2013/01/how-to-write-maintainable-javascript-or.html

fmsf
  • 36,317
  • 49
  • 147
  • 195