Singleton in JavaScript

Discussion in 'Javascript' started by JohnS, Aug 21, 2003.

  1. JohnS

    JohnS Guest

    Hi,

    A lot of functions (classes) in my JavaScript app are singletons. So, I have
    been exploring ways making JavaScript functions singletons. I thought I'ld
    run one idea past you all and get some feed back.

    The usual method of making singletons is to have a static member that
    returns one instance of the class. But, JavaScript has no notion of static.
    The closest it has is prototype functions.

    // The singleton class
    function Single() {
    // call the "static" GetInstance()
    return Single.prototype.GetInstance();
    }

    // The only instance.
    Single.prototype._single = null;

    // static function
    Single.prototype.GetInstance = function() {
    if( !Single.prototype._single ) {
    Single.prototype._single = this;
    }
    return Single.prototype._single;
    }
    ----------

    So, "new Single() == new Single()" is true.
    Or "new Single() == Single.prototype.GetInstance()"

    What do you all think? Is the "new Single()" going to be confusing? Is there
    are way to do "Single.GetInstance()"? I think the prototype version is
    unweildy.

    -------------------------------------------------------------

    When can I refer to prototype functions or prototypes full stop? It appears
    that "this.GetInstance" exists in "new Single()", but I can't call it.

    JohnS
     
    JohnS, Aug 21, 2003
    #1
    1. Advertising

  2. "JohnS" <> wrote in message
    news:3f4472bb$0$28123$...
    <snip>
    >... . But, JavaScript has no notion of static.
    > The closest it has is prototype functions.

    <snip>

    In JavaScript public static members are created a properties of the
    function object that represents the constructor:-

    function Single() {
    if(!Single.instance){
    //construct objectc
    Single.instance = this;
    }
    return Single.instance;
    }

    Single.instance = null; //public static member

    - and private static members may be emulated by forming a closure with
    the constructor:-

    var Single = (function(){
    var instance = null; //private static member
    return (function(){ //return the constructor function
    if(!instance){
    //construct object
    instance = this;
    }
    return instance;
    });
    })(); //inline execution of anonymous function

    - (or the prototype, but it is cleaner and more flexible with the
    constructor).

    >... Is there
    > are way to do "Single.GetInstance()"?

    <snip>

    Yes, public static methods are completely normal:-

    Single.GetInstance = function(){
    . . . //function body
    }

    Richard.
     
    Richard Cornford, Aug 21, 2003
    #2
    1. Advertising

  3. JohnS

    JohnS Guest

    That's great. So, I can drop the prototype and just put GetInstance straight
    into the function. I didn't know that.

    The second example threw me for a bit. It seemed like it should return a
    typeof "function" . But, it returns a typeof "object". So, it's contructing
    an object without using the "new" keyword. Strange.

    It seems to mean, that when you call a straight function, the function
    becomes an object and then executes. If you return "this", you have a
    function instance/object.

    Also, if you have an inner function, "this" refers to the outer "this".

    Thanks for your help.

    JohnS

    ----- Original Message -----
    From: "Richard Cornford" <>
    Newsgroups: comp.lang.javascript
    Sent: Thursday, August 21, 2003 6:01 PM
    Subject: Re: Singleton in JavaScript


    > "JohnS" <> wrote in message
    > news:3f4472bb$0$28123$...
    > <snip>
    > >... . But, JavaScript has no notion of static.
    > > The closest it has is prototype functions.

    > <snip>
    >
    > In JavaScript public static members are created a properties of the
    > function object that represents the constructor:-
    >
    > function Single() {
    > if(!Single.instance){
    > //construct objectc
    > Single.instance = this;
    > }
    > return Single.instance;
    > }
    >
    > Single.instance = null; //public static member
    >
    > - and private static members may be emulated by forming a closure with
    > the constructor:-
    >
    > var Single = (function(){
    > var instance = null; //private static member
    > return (function(){ //return the constructor function
    > if(!instance){
    > //construct object
    > instance = this;
    > }
    > return instance;
    > });
    > })(); //inline execution of anonymous function
    >
    > - (or the prototype, but it is cleaner and more flexible with the
    > constructor).
    >
    > >... Is there
    > > are way to do "Single.GetInstance()"?

    > <snip>
    >
    > Yes, public static methods are completely normal:-
    >
    > Single.GetInstance = function(){
    > . . . //function body
    > }
    >
    > Richard.
    >
    >
     
    JohnS, Aug 25, 2003
    #3
  4. JohnS

    asdf asdf Guest

    Hi, I just wanted to add a tiny thing that I'm not sure was mentioned.
    Another way of declaring a static function is:

    function Single.GetInstance() {
    ....
    }

    This way your call stack will have a named function instead of an
    anonymous one.



    "Richard Cornford" <> wrote in message news:<bi1u91$be2$1$>...
    >
    > Single.GetInstance = function(){
    > . . . //function body
    > }
    >
    > Richard.
     
    asdf asdf, Aug 26, 2003
    #4
  5. (asdf asdf) writes:

    > Hi, I just wanted to add a tiny thing that I'm not sure was mentioned.
    > Another way of declaring a static function is:
    >
    > function Single.GetInstance() {
    > ...
    > }


    Not in ECMAScript v3 or any Javascript I have seen. It doesn't appear
    to work in JScript.NET (which implements the proposed ECMAScript v4).

    It is just a syntax error. It would be very nice is that syntax was
    supported, but it isn't.

    > This way your call stack will have a named function instead of an
    > anonymous one.


    You could write either

    function getInstance() {...}
    Single.GetInstance = getInstance;

    or

    Single.GetInstacne = function GetInstance() {...}

    Just remember that there is no difference between a "named" function
    and an anonymous one. It is just a function object, which is an anonymous
    value, that has been assigned to a variable.

    /L 'please don't top post'.
    --
    Lasse Reichstein Nielsen -
    Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, Aug 26, 2003
    #5
  6. "JohnS" <> wrote in message
    news:3f498d74$0$15131$...
    <snip>
    >The second example threw me for a bit. It seemed like it should
    >return a typeof "function" . But, it returns a typeof "object".
    >So, it's contructing an object without using the "new" keyword.
    >Strange.


    When you say 'it returns a typeof "object"', what do you men by "it".
    Single should be a reference to a function (the constructor returned by
    the incline function expression call), as a constructor, calling - new
    Single(); - will return an object. A new object the first time it is
    called and that same object on every subsequent call. However, if you
    call any custom JavaScript constructor without using the - new - keyword
    you will not get a new object constructed and there is every chance that
    the function will execute as global code and the - this - keyword will
    refer to the global object.

    >It seems to mean, that when you call a straight function, the
    >function becomes an object and then executes. If you return
    >"this", you have a function instance/object.


    If you call a global function the - this - keyword will refer to the
    global object, if - this - is returned then the object returned will be
    the global object.

    >Also, if you have an inner function, "this" refers to the
    >outer "this".


    No it will not. For inner functions - this - could be one of may
    objects. If the inner function is assigned as a method of an object
    (including function objects) then - this - refers to that object, else
    an inner function - this - will be the global object unless that inner
    function is called as a constructor using the - new - keyword, in which
    case - this - refers to the new object. The specifics are described in
    the ECMA Script specification.

    Richard.
     
    Richard Cornford, Aug 26, 2003
    #6
  7. JohnS

    JohnS Guest

    Single is a reference to a function. But calling Single(), returns an
    object. In fact, Single() == new Single(), always.

    I now understand why I was confused. When calling Single(), the instance
    variable was inited with the global this. Arghh!
    So, you are right, you need the new keyword to get a new this. But, after
    the first call of new Single(), you can call Single() to get
    the instance.

    I think I'll change the constructor to create a new Single() if this is
    global.

    Thanks for your explainations.

    ----------------------------------------------------------------------------
    -------
    Here the the test code I used:
    note: If you call Single() before new Single(), isObjectGlobal() returns
    true.


    function p( msg ) {
    document.write( msg + "<BR>" );
    }

    var gThis = this;
    function isObjectGlobalThis( myThis ) {
    return myThis == gThis;
    }

    // Singleton
    var Single = (function(){
    var instance = null; //private static member
    return (function(){ //return the constructor function
    if(!instance){
    //construct object
    p( "Constructing this" );
    instance = this;
    }
    p( "Returning this" );
    return instance;
    });
    })(); //inline execution of anonymous function


    function test() {

    p( "Calling new Single()" );
    single1 = new Single();
    p( "" );

    p( "Calling Single()" );
    single2 = Single();
    p( "" );


    p( "typeof Single: " + typeof Single );
    p( "typeof Single(): " + typeof single1 );
    p( "typeof new Single(): " + typeof single2 );
    p( "" );

    p( "Single() == new Single(): " + (single1 == single2) );
    p( "" );

    p( "isObjectGlobalThis( test ): " + isObjectGlobalThis( this ) );

    p( "isObjectGlobalThis( Single() ): " + isObjectGlobalThis( single1 ) );
    p( "isObjectGlobalThis( new Single() ): " + isObjectGlobalThis(
    single2 ) );
    }

    --------------------------------------------------------------------------
    Output is:
    Calling new Single()
    Constructing this
    Returning this

    Calling Single()
    Returning this

    typeof Single: function
    typeof Single(): object
    typeof new Single(): object

    Single() == new Single(): true

    isObjectGlobalThis( test ): true
    isObjectGlobalThis( Single() ): false
    isObjectGlobalThis( new Single() ): false


    "Richard Cornford" <> wrote in message
    news:bign9k$n44$1$...
    > "JohnS" <> wrote in message
    > news:3f498d74$0$15131$...
    > <snip>
    > >The second example threw me for a bit. It seemed like it should
    > >return a typeof "function" . But, it returns a typeof "object".
    > >So, it's contructing an object without using the "new" keyword.
    > >Strange.

    >
    > When you say 'it returns a typeof "object"', what do you men by "it".
    > Single should be a reference to a function (the constructor returned by
    > the incline function expression call), as a constructor, calling - new
    > Single(); - will return an object. A new object the first time it is
    > called and that same object on every subsequent call. However, if you
    > call any custom JavaScript constructor without using the - new - keyword
    > you will not get a new object constructed and there is every chance that
    > the function will execute as global code and the - this - keyword will
    > refer to the global object.
    >
    > >It seems to mean, that when you call a straight function, the
    > >function becomes an object and then executes. If you return
    > >"this", you have a function instance/object.

    >
    > If you call a global function the - this - keyword will refer to the
    > global object, if - this - is returned then the object returned will be
    > the global object.
    >
    > >Also, if you have an inner function, "this" refers to the
    > >outer "this".

    >
    > No it will not. For inner functions - this - could be one of may
    > objects. If the inner function is assigned as a method of an object
    > (including function objects) then - this - refers to that object, else
    > an inner function - this - will be the global object unless that inner
    > function is called as a constructor using the - new - keyword, in which
    > case - this - refers to the new object. The specifics are described in
    > the ECMA Script specification.
    >
    > Richard.
    >
    >
     
    JohnS, Aug 27, 2003
    #7
  8. "JohnS" <> wrote in message
    news:3f4bf54f$0$15136$...
    >Single is a reference to a function. But calling Single(),
    >returns an object. In fact, Single() == new Single(), always.


    As I wrote the Single class it was intended that all calls to it use
    the - new - keyword.

    >I now understand why I was confused. When calling Single(),
    >the instance variable was inited with the global this. Arghh!
    >So, you are right, you need the new keyword to get a new this.
    >But, after the first call of new Single(), you can call
    >Single() to get the instance.


    If you can guarantee that the first call uses - new - and that all calls
    that do not use - new - happen after that initial call then you probably
    do not want a class at all. Maybe one object assigned to a global
    property will do the job sufficiently:-

    var Single = {
    prop1:1,
    prop2:"anyString",
    getProp1:function(){
    return this.prop1;
    },
    setProp1:function(x){
    this.prop1 = x;
    },
    getProp2:function(){
    return prop2;
    }
    }

    - so all code could just refer to the same object by the identifier
    Single.

    >I think I'll change the constructor to create a new Single()
    >if this is global.

    <snip>

    You could do that but you would need a reliable test for the global
    object and that would be extra work. If you just want to call a
    function - Single() - (without the - new - keyword) and have it always
    return the same (non-global) object then there are many aproaches, for
    example:-

    var Single = (function(){
    var instance = null;
    function InnerSingle(){
    //actual constructor.
    this.X = "something";
    ... //constructor function body
    }
    InnerSingle.prototype.getX = function(){
    return this.X; //example method;
    }
    return (function(){
    if(!instance){
    instance = new InnerSingle();
    }
    return instance;
    })
    })();

    called as - var obj = Single();

    - here the real class is the InnerSingle class, whose constructor is
    private (inaccessible outside the closure). The rest is just a wrapper
    to make acquiring a reference to the one instance convenient. There are
    probably at lest another half a dozen ways of achieving the same, using
    object literal within the closure, for example:-

    var Single = (function(){
    var instance = null;
    return (function(){
    if(!instance){
    instance = {
    X:"something",
    getX:function(){
    return this.X;
    }
    };
    }
    return instance;
    })
    })();

    -or-

    var Single = (function(){
    var instance = {
    X:"something",
    getX:function(){
    return this.X;
    }
    };
    return (funciton(){
    return instance;
    })
    })();

    called as - var obj = Single();

    Alternatively you could return to your original public static -
    getInstance - approach. In JavaScript you cannot have a "class" without
    a public constructor, while a singleton probably should not have a
    public constructor. However, a similar approach as used above could
    emulate a class with a public static getInstance method but no
    constructor. In this case the - Single - object is not a function (so it
    cannot be called as a constructor), instead it is an object with one
    public method:-

    var Single = (function(){
    var instance = null;
    function InnerSingle(){
    //actual constructor.
    this.X = "something";
    ... //constructor function body
    }
    InnerSingle.prototype.getX = function(){
    return this.X; //example method;
    }
    return ({
    getInstance:function(){
    if(!instance){
    instance = new InnerSingle();
    }
    return instance;
    }
    });
    })();

    called as - var obj = Single.getInstance();

    - the outward appearance and behaviour is that of a class without a
    public constructor but with a public static - getInstace - method.

    A similar structure could also be used to implement a class with no
    public constructor and a factory method that returned a unique new
    object on each invocation.

    Richard.
     
    Richard Cornford, Aug 27, 2003
    #8
  9. JohnS

    asdf asdf Guest

    Hi -- I believe it works in IE6, which is all I code against. Thanks,
    Ron

    (asdf asdf) wrote in message news:<>...
    > Hi, I just wanted to add a tiny thing that I'm not sure was mentioned.
    > Another way of declaring a static function is:
    >
    > function Single.GetInstance() {
    > ...
    > }
    >
    > This way your call stack will have a named function instead of an
    > anonymous one.
     
    asdf asdf, Aug 27, 2003
    #9
  10. (asdf asdf) writes:

    > Hi -- I believe it works in IE6, which is all I code against.


    You are actually right.

    function x(){}
    function x.y (){alert('foo');}
    x.y(); // alerts "foo"

    It is important that x is a function. It doesn't work if it is just a
    normal object (which was what I first tried).

    /L
    --
    Lasse Reichstein Nielsen -
    Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, Aug 27, 2003
    #10
  11. "Lasse Reichstein Nielsen" <> wrote in message
    news:eek:...
    <snip>
    > function x(){}
    > function x.y (){alert('foo');}
    > x.y(); // alerts "foo"
    >
    > It is important that x is a function. It doesn't work if it is
    >just a normal object (which was what I first tried).


    It appears that it can work with at leas some objects on IE. I have
    seen:-

    function window.onload(){
    . . . //function body
    }

    - for example, as a way of defining an onload handler.

    But as ECMA Script defines methods for achieving the same effect (that
    work on IE) it does not seem like a good idea to be using a syntax that
    is not part of the specification even when authoring for exclusively IE.
    It would just be another bad habit that would need to be un-learnt prior
    to successfully writing cross-browser code.

    Richard.
     
    Richard Cornford, Aug 27, 2003
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Proton Projects - Moin

    Singleton - Whether Cloneable overrides Singleton

    Proton Projects - Moin, Mar 26, 2007, in forum: Java
    Replies:
    4
    Views:
    3,256
    Proton Projects - Moin
    Mar 27, 2007
  2. Wilhelm
    Replies:
    1
    Views:
    167
  3. Trans
    Replies:
    12
    Views:
    280
    Robert Klemme
    Sep 14, 2007
  4. Paul McMahon
    Replies:
    3
    Views:
    206
    David A. Black
    Jun 9, 2008
  5. Charles Oliver Nutter

    Singleton methods without the singleton class

    Charles Oliver Nutter, Mar 15, 2010, in forum: Ruby
    Replies:
    4
    Views:
    204
    Charles Oliver Nutter
    Mar 22, 2010
Loading...

Share This Page