0

Can someone explain

  1. why a and b refer to the same object here?

What if I want to create two different instances of Singleton object(I know it is against the design pattern, but just for learning purpose), what should I modify?

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

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

var a = new MySingletonClass()
var b = MySingletonClass()
Print( a === b ); // prints: true
Sebastien C.
  • 4,649
  • 1
  • 21
  • 32
Blake
  • 7,367
  • 19
  • 54
  • 80
  • That's some weird syntax you have here. I don't know what `new function...` does but it definitely does not return a function (it returns an object at least under Chrome). So `new Singleton()` should throw an exception. On the other hand if `new function` is just a mistake (and it is simply `function`) then these instances won't be the same. – freakish Jun 26 '14 at 10:16
  • It's not quite right. Change the order of `var a = ...` and `var b = ...` and it will print false. – fgb Jun 26 '14 at 12:05
  • See http://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript for some working implementations – fgb Jun 26 '14 at 12:08
  • I was following the guide on google, https://code.google.com/p/jslibs/wiki/JavascriptTips#Singleton_pattern – Blake Jun 26 '14 at 12:49

2 Answers2

1

No idea what are you trying to achieve here, but proper singleton implementation should not allow creating new Singleton() by calling its constructor

Following code implements the singleton in correct way IMHO: `

var Singleton =  new function () 
{
    var instance = this;
    this.getInstance = function()
    {
        if(!instance)
            instance = new Singleton();

        return instance;
    }
}

//var instance1 = new Singleton();// should not work
//var instance2 = new Singleton();
//alert( instance2 == instance1 ); 
alert (Singleton.getInstance() == Singleton.getInstance()) // returns true

`

Igor Iris
  • 66
  • 3
0

This implementation is slightly tricky: MySingletonClass acts as a function, an object, and a constructor in different contexts. Also the constructor sometimes returns a different object, instead of modifying this as usual.

The singleton object is stored as a property of the function MySingletonClass i.e. MySingletonClass._singletonInstance.

MySingletonClass is called as either a function (MySingletonClass()) or a constructor (new MySingletonClass()). When it is called, the object may or may not already exist. Let's look at these cases:

  • Constructor - Object exists

    arguments.callee is just the function so you could use MySingletonClass._singletonInstance instead. The first line checks if the object exists, and then the second returns it. Because an object is returned from the constructor, the result of the new expression is that object.

  • Constructor - Object does not exist

    The singleton object is set to this, the object that is currently being constructed, and then this is initialized by adding some functions (Foo etc). The call to the constructor then evaluates to this. The object now exists so it won't be initialized again.

  • Function - Object exists

    arguments.callee is still the function so the object is returned as before.

  • Function - Object does not exist

    Here, this is the global object, so the _singletonInstance variable and the Foo functions are added to the global object. The function doesn't return anything so b becomes undefined. This is not the behavior you want.

In the first three cases, the object MySingletonClass._singletonInstance is initialized if it doesn't exist, and then the calling expression evaluates to that instance.

As for multiple instances, it wouldn't make much sense to create multiple instances of a singleton. How would you specify which instance to get? If you want multiple instances, just remove the arguments.callee code at the beginning and you have a non-singleton constructor.

fgb
  • 18,439
  • 2
  • 38
  • 52