Singleton in JavaScript

J

JohnS

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
 
R

Richard Cornford

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

JohnS

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" <[email protected]>
Newsgroups: comp.lang.javascript
Sent: Thursday, August 21, 2003 6:01 PM
Subject: Re: Singleton in JavaScript
 
A

asdf asdf

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

Lasse Reichstein Nielsen

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

Richard Cornford

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

JohnS

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
 
R

Richard Cornford

JohnS said:
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.
 
L

Lasse Reichstein Nielsen

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
 
R

Richard Cornford

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Singleton 29
singleton question 6
singleton 26
Singleton Pattern 7
Instance() in Singleton Class Question 2
Webview Javascript functions? 1
Javascript programming in TheThingsNetwork 1
Singleton initialization DCLP 1

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,140
Latest member
SweetcalmCBDreview
Top