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
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.
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
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>...
> 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.'
The ECMAScript standard does not permit this form. I think it should, but it
doesn't.
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.
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...
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.
b0b...@yahoo.com (asdf asdf) wrote in message news:<6f24588b.03082...@posting.google.com>...
> 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
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.