Singleton in JavaScript

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • JohnS

    Singleton in JavaScript

    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.prototyp e.GetInstance() ;
    }

    // The only instance.
    Single.prototyp e._single = null;

    // static function
    Single.prototyp e.GetInstance = function() {
    if( !Single.prototy pe._single ) {
    Single.prototyp e._single = this;
    }
    return Single.prototyp e._single;
    }
    ----------

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

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

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

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

    JohnS


  • Richard Cornford

    #2
    Re: Singleton in JavaScript

    "JohnS" <jsietsma_publi c@optusnet.com. au> wrote in message
    news:3f4472bb$0 $28123$afc38c87 @news.optusnet. com.au...
    <snip>[color=blue]
    >... . But, JavaScript has no notion of static.
    > The closest it has is prototype functions.[/color]
    <snip>

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

    function Single() {
    if(!Single.inst ance){
    //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).
    [color=blue]
    >... Is there
    > are way to do "Single.GetInst ance()"?[/color]
    <snip>

    Yes, public static methods are completely normal:-

    Single.GetInsta nce = function(){
    . . . //function body
    }

    Richard.


    Comment

    • JohnS

      #3
      Re: Singleton in JavaScript


      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" <Richard@litote s.demon.co.uk>
      Newsgroups: comp.lang.javas cript
      Sent: Thursday, August 21, 2003 6:01 PM
      Subject: Re: Singleton in JavaScript

      [color=blue]
      > "JohnS" <jsietsma_publi c@optusnet.com. au> wrote in message
      > news:3f4472bb$0 $28123$afc38c87 @news.optusnet. com.au...
      > <snip>[color=green]
      > >... . But, JavaScript has no notion of static.
      > > The closest it has is prototype functions.[/color]
      > <snip>
      >
      > In JavaScript public static members are created a properties of the
      > function object that represents the constructor:-
      >
      > function Single() {
      > if(!Single.inst ance){
      > //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).
      >[color=green]
      > >... Is there
      > > are way to do "Single.GetInst ance()"?[/color]
      > <snip>
      >
      > Yes, public static methods are completely normal:-
      >
      > Single.GetInsta nce = function(){
      > . . . //function body
      > }
      >
      > Richard.
      >
      >[/color]


      Comment

      • asdf asdf

        #4
        Re: Singleton in JavaScript

        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.GetInsta nce() {
        ....
        }

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



        "Richard Cornford" <Richard@litote s.demon.co.uk> wrote in message news:<bi1u91$be 2$1$8300dec7@ne ws.demon.co.uk> ...[color=blue]
        >
        > Single.GetInsta nce = function(){
        > . . . //function body
        > }
        >
        > Richard.[/color]

        Comment

        • Lasse Reichstein Nielsen

          #5
          Re: Singleton in JavaScript

          b0b0b0b@yahoo.c om (asdf asdf) writes:
          [color=blue]
          > 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.GetInsta nce() {
          > ...
          > }[/color]

          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.
          [color=blue]
          > This way your call stack will have a named function instead of an
          > anonymous one.[/color]

          You could write either

          function getInstance() {...}
          Single.GetInsta nce = getInstance;

          or

          Single.GetInsta cne = 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 - lrn@hotpop.com
          Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit. html>
          'Faith without judgement merely degrades the spirit divine.'

          Comment

          • Richard Cornford

            #6
            Re: Singleton in JavaScript

            "JohnS" <jsietsma_publi c@optusnet.com. au> wrote in message
            news:3f498d74$0 $15131$afc38c87 @news.optusnet. com.au...
            <snip>[color=blue]
            >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.[/color]

            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.
            [color=blue]
            >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.[/color]

            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.
            [color=blue]
            >Also, if you have an inner function, "this" refers to the
            >outer "this".[/color]

            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.


            Comment

            • JohnS

              #7
              Re: Singleton in JavaScript

              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 isObjectGlobalT his( 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( "Constructi ng 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( "isObjectGlobal This( test ): " + isObjectGlobalT his( this ) );

              p( "isObjectGlobal This( Single() ): " + isObjectGlobalT his( single1 ) );
              p( "isObjectGlobal This( new Single() ): " + isObjectGlobalT his(
              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

              isObjectGlobalT his( test ): true
              isObjectGlobalT his( Single() ): false
              isObjectGlobalT his( new Single() ): false


              "Richard Cornford" <Richard@litote s.demon.co.uk> wrote in message
              news:bign9k$n44 $1$8300dec7@new s.demon.co.uk.. .[color=blue]
              > "JohnS" <jsietsma_publi c@optusnet.com. au> wrote in message
              > news:3f498d74$0 $15131$afc38c87 @news.optusnet. com.au...
              > <snip>[color=green]
              > >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.[/color]
              >
              > 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.
              >[color=green]
              > >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.[/color]
              >
              > 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.
              >[color=green]
              > >Also, if you have an inner function, "this" refers to the
              > >outer "this".[/color]
              >
              > 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.
              >
              >[/color]


              Comment

              • Richard Cornford

                #8
                Re: Singleton in JavaScript

                "JohnS" <jsietsma_publi c@optusnet.com. au> wrote in message
                news:3f4bf54f$0 $15136$afc38c87 @news.optusnet. com.au...[color=blue]
                >Single is a reference to a function. But calling Single(),
                >returns an object. In fact, Single() == new Single(), always.[/color]

                As I wrote the Single class it was intended that all calls to it use
                the - new - keyword.
                [color=blue]
                >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.[/color]

                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:"anyStrin g",
                getProp1:functi on(){
                return this.prop1;
                },
                setProp1:functi on(x){
                this.prop1 = x;
                },
                getProp2:functi on(){
                return prop2;
                }
                }

                - so all code could just refer to the same object by the identifier
                Single.
                [color=blue]
                >I think I'll change the constructor to create a new Single()
                >if this is global.[/color]
                <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.pro totype.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.pro totype.getX = function(){
                return this.X; //example method;
                }
                return ({
                getInstance:fun ction(){
                if(!instance){
                instance = new InnerSingle();
                }
                return instance;
                }
                });
                })();

                called as - var obj = Single.getInsta nce();

                - 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.


                Comment

                • asdf asdf

                  #9
                  Re: Singleton in JavaScript

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

                  b0b0b0b@yahoo.c om (asdf asdf) wrote in message news:<6f24588b. 0308251912.7635 88d7@posting.go ogle.com>...[color=blue]
                  > 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.GetInsta nce() {
                  > ...
                  > }
                  >
                  > This way your call stack will have a named function instead of an
                  > anonymous one.[/color]

                  Comment

                  • Lasse Reichstein Nielsen

                    #10
                    Re: Singleton in JavaScript

                    b0b0b0b@yahoo.c om (asdf asdf) writes:
                    [color=blue]
                    > Hi -- I believe it works in IE6, which is all I code against.[/color]

                    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 - lrn@hotpop.com
                    Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit. html>
                    'Faith without judgement merely degrades the spirit divine.'

                    Comment

                    • Richard Cornford

                      #11
                      Re: Singleton in JavaScript

                      "Lasse Reichstein Nielsen" <lrn@hotpop.com > wrote in message
                      news:oeybjztl.f sf@hotpop.com.. .
                      <snip>[color=blue]
                      > 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).[/color]

                      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.


                      Comment

                      Working...