Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Singleton in JavaScript

1 view
Skip to first unread message

JohnS

unread,
Aug 21, 2003, 3:20:39 AM8/21/03
to
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


Richard Cornford

unread,
Aug 21, 2003, 4:01:37 AM8/21/03
to
"JohnS" <jsietsm...@optusnet.com.au> wrote in message
news:3f4472bb$0$28123$afc3...@news.optusnet.com.au...
<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

unread,
Aug 25, 2003, 12:15:59 AM8/25/03
to

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

asdf asdf

unread,
Aug 25, 2003, 11:12:55 PM8/25/03
to
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" <Ric...@litotes.demon.co.uk> wrote in message news:<bi1u91$be2$1$8300...@news.demon.co.uk>...

Lasse Reichstein Nielsen

unread,
Aug 26, 2003, 6:27:16 AM8/26/03
to
b0b...@yahoo.com (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 - l...@hotpop.com
Art D'HTML: <URL:http://www.infimum.dk/HTML/randomArtSplit.html>
'Faith without judgement merely degrades the spirit divine.'

Douglas Crockford

unread,
Aug 26, 2003, 9:13:31 AM8/26/03
to
> 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.

The ECMAScript standard does not permit this form. I think it should, but it
doesn't.

http://www.ecmascript.org/

Richard Cornford

unread,
Aug 26, 2003, 6:34:26 PM8/26/03
to
"JohnS" <jsietsm...@optusnet.com.au> wrote in message
news:3f498d74$0$15131$afc3...@news.optusnet.com.au...
<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

unread,
Aug 26, 2003, 8:03:43 PM8/26/03
to
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" <Ric...@litotes.demon.co.uk> wrote in message

news:bign9k$n44$1$8300...@news.demon.co.uk...

Richard Cornford

unread,
Aug 26, 2003, 10:18:53 PM8/26/03
to
"JohnS" <jsietsm...@optusnet.com.au> wrote in message
news:3f4bf54f$0$15136$afc3...@news.optusnet.com.au...

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


asdf asdf

unread,
Aug 27, 2003, 1:06:21 AM8/27/03
to
Hi -- I believe it works in IE6, which is all I code against. Thanks,
Ron

b0b...@yahoo.com (asdf asdf) wrote in message news:<6f24588b.03082...@posting.google.com>...

Lasse Reichstein Nielsen

unread,
Aug 27, 2003, 3:59:34 AM8/27/03
to
b0b...@yahoo.com (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

Richard Cornford

unread,
Aug 27, 2003, 1:14:19 PM8/27/03
to
"Lasse Reichstein Nielsen" <l...@hotpop.com> wrote in message
news:oeybjz...@hotpop.com...
<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.


0 new messages