But other then this, what can I actually use it for? Examples of usage? Or
is it just a curiosity? :)
Regards,
Svend
(new to comp.lang.javascript!)
>But other then this, what can I actually use it for? Examples
>of usage? Or is it just a curiosity? :)
Suppose that a JavaScript object is instantiated and in that process it
used DOM Node creation methods to create an HTML element and insert it
into a document. That element has an event handling function and that
function needs to call a method of the JavaScript Object instance that
created the element.
function myObject(){ //constructor
...
var txtEl = document.createElement('INPUT');
txtEl.type = 'text';
txtEl.name = 'test1';
txtEl.value = '';
txtEl.onchange = myObject.callDoOnChange(this);
... // insert the Node into the document.
...
}
myObject.callDoOnChange = function(obj){
return function(ev){
obj.doOnChange(ev);
};
};
myObject.prototype.doOnChange = function(ev){
ev = ev|window.event;
...
};
Thus the closure allows the DOM element to anonymously refer back to the
JavaScript Object instance that created it.
But any mechanism that allows JavaScript Objects to have private members
is more than just a curiosity.
Richard.
Svend Tofte <svend...@svendtofte.com> writes:
> So, I've recently become aware, of the subject of closures in
> JavaScript. And if I understand things correct, this phenomenon is
> basicly what makes it possible to have private/public information in
> JavaScript objects.
> But other then this, what can I actually use it for? Examples of
> usage? Or is it just a curiosity? :)
Closures is an old concept from functional programming. It all boils down
to having one element that contains both 1) program code to be executed and
2) the values of the "free variables" in the code.
The code
window.alert(x)
contains two names: "window" and "x". Without knowing which values
these refer to, the code can not be executed. The function code
function(){window.alert(x)}
evaluates to a function *value* that is also a closure. It contains
both the code "window.alert(x)" and the variables named "window" and "x"
*at the point where the function defined*.
Example:
The function "map" takes an array (e.g. [1,2,3]) and a function, f,
and return a new array (for [1,2,3] it will be [f(1),f(2),f(3)] ).
function map(arr,f) {
var res = [];
for (var i=0;i<arr.len;i++) {
res[i]=fun(arr[i]);
}
return res;
}
Now, if we want to get a new array where each element is incremented by
one, we can write
map(myArray,function(x){return x+1))
If we want to increment by two, we write
map(myArray,function(x){return x+2))
Soo we notice that we want to add all kinds of numbers, so instead of
writing one function for each, we can write a generic "add to array"
function:
function addToArray(arr,num) {
var numInc = function(x) {return x+num;};
return map(arr,numInc);
}
Notice the inner function. It is not just *one* function. It is one
function for each possible value of "num". Each time we call addToArray,
we create a new function value, a new closure, containing the current
value of "num".
We could also make a function to create an incrementor:
function createIncrementor(num) {
return function(x) {return x+num;};
}
To make a function that adds one to its argument, we write
var incOne = createIncrementor(1)
To make one that adds 1000000, we write
var incMill = createIncrementor(1000000)
This is what closures are good for: Functions that create other functions.
You don't need closures. Instead we could pass around a pair of closed
function and parameters like
[function(num,x){return x+num;},1000000]
and then plug in the value only when we call the function. It's just not
as pretty.
Say if I make no sense at all!
/L 'functional programmer'
--
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.'
Your example is very helpful. However, since the goal is to capture
the current object reference as part of state of the anonymous
function, wouldn't it simplify if the assignment was coded as:
...
var o = this; // Copy current "this" object reference
txtEl.onchange = function(e) {o.doOnChange(e);};
...
Or am I missing something here?
../rh
First, what is "e"? I think you meant
txtEl.onchange = function() {o.doOnChange(txtEl);};
In any case, your suggestion leaks memory every time you call the
myObject() constructor. JScript can break circular references that
only involve JScript references, but it cannot break circular
references that involve external references like ActiveX objects and
elements in the IE DOM. That code creates a circular reference that
cannot be broken, presumably, until the page is unloaded. I had a
case before where the memory would not be freed until the browser was
shutdown.
What happens when you use a nested function like you suggest is that
the closure is created which allows the nested function to access the
local variables of the outer function. Because of that, basically you
end up with this chain:
txtEl --> INPUT element --> (anonymous function) --> txtEl
The local variable, txtEl is assigned a reference to an INPUT element;
it's onchange property is assigned a function reference; and that
function -- through the closure -- references the txtEl variable.
Regards,
Steve
Either approach will be functional, whether one is simpler that the
other would depend on the bigger context. The Inner function in the
constructor has access to all or the constructor's parameters and
variables. In this case the closure only actually needs a reference to
the object instance but I don't see it doing any harm if the function
has access to more than it uses.
On the other hand a separate function that forms a closure with just the
object instance in it might be more re-usable. It could be used by more
than one class and a slight modification could render it quite generic,
consider:-
//called as
txtEl.onchange = setEventHandler(this, 'doOnChange');
//defined as
function setEventHandler(obj, sMethodName){
return function(ev){
obj[sMethodName](ev);
};
}
Now given a requirement to call different instance methods from
different event handlers in different classes, the external closure is
much simpler than filling each constructor with multiple inner
functions. (Although a private instance method in the constructor could
do the same for one class).
There is also the possibility of wanting to associate the instance with
the event handler from an instance method of the object instead of the
constructor. The instance method might have many parameters and local
variables so if it was to form a closure the result would be much bigger
(consume more memory) than the closure formed with a separate function
call.
Then there is Steve's cyclic references problem. Which I gather from
previous discussions on the subject is a real killer with ActiveX. It
seems that it would often be a good idea to include, and use, explicit
'destroy' functions with DHTML and ActiveX based JavaScript objects that
use closures. To free up any references from JavaScript objects
before/as a page unloads.
Richard.
"e" is the (optional) event object, as per "ev" in the original. As
was done there, it is passed through to the prototype function for
handling in context of the originating myObject instantiation.
>
> In any case, your suggestion leaks memory every time you call the
> myObject() constructor. JScript can break circular references that
> only involve JScript references, but it cannot break circular
> references that involve external references like ActiveX objects and
> elements in the IE DOM. That code creates a circular reference that
> cannot be broken, presumably, until the page is unloaded. I had a
> case before where the memory would not be freed until the browser was
> shutdown.
>
> What happens when you use a nested function like you suggest is that
> the closure is created which allows the nested function to access the
> local variables of the outer function. Because of that, basically you
> end up with this chain:
> txtEl --> INPUT element --> (anonymous function) --> txtEl
> The local variable, txtEl is assigned a reference to an INPUT element;
> it's onchange property is assigned a function reference; and that
> function -- through the closure -- references the txtEl variable.
>
Points well taken regarding circularity and the awareness and cautions
that are required in that area.
In the particular example given though, the myObject constructor is
only called to create elements in the form, and so you would want the
references and memory to be maintained until the page unloads.
Whether tieing things across the DOM boundary in the manner of the
original example, or as modified, is a good or bad thing is another
debate :-).
../rh
> Regards,
> Steve
That of course requires that multiple objects or classes have methods
called by the window.onunload event. Not a problem if the browser
supports addEventListener. However, as the subject of this thread is
uses that closures may be put to, this closure offering from Yep might
of interest:-
<URL:
http://groups.google.com/groups?selm=d2d855ea.0211180417.44bcd1d4%40post
ing.google.com >
function _E(obj, evt, func){
if(obj[evt]) {
obj[evt]=function(_f,_g){
return function(){
_f.apply(this,arguments);
_g.apply(this,arguments);
};
}(obj[evt],func);
}else obj[evt]=func;
}
Unfortunately it might also require a Function.prototype.apply emulation
on older IE versions, but if that is only for use with event handlers it
could be a very simple emulation. Yep has also kept this function very
general and is making no consideration of return values. That would not
be a problem when used with window.onunload as not return values are
relevant. The - apply - method would probably also not be necessary with
the window.onunload event as it would not matter whether the _f and _g
functions where executed in the global context because that is the
window anyway.
So, maybe (untested):-
function _E(func){
if(window.onunload){
window.onunload = function(_f, _g){
return function(ev){
_f(ev);
_g(ev);
};
}(window.onunload, func);
}else window.onunload = func;
}
Thus (and assuming that any HTML defined onunload handlers are already
set up and no other script is going to directly assign window.onunload)
each instance can arrange that its own destroy/finalize method is called
with the onunload event.
Based on the recent discussion of JavaScript static (and particularly,
private static) members, I think that it would be possible to have the
class track its own instances and have onunload call a class method that
could destroy/finalize all of its instances at once. But that would only
be worth while if it was expected that there be a lot of instances.
Richard.
Agreed. My question was more in the context of the original post,
where I think there was a need to be able to grasp a new concept. In
that case simpler is usually better.
As an initial response to the OP, I would have preferred to see a
definition of closure, followed by a simple example or two
illustrating how to create a closure, and how it could be effectively
applied (as done by Lasse). An even richer response might have
included a word or two about how closure in Javascript differs from
that in a class-based language, if indeed such a difference does
exist.
That's not to diminish the excellent information that you've provided
in going into the higher level detail of your examples. Perhaps
though, particularly if I had asked a better question at the outset,
there could have been a bit more of a walk before the run here.
../rh
Reading the OP, my impression was that the question was from someone who
knew what a closure was and understood their application in creating
private instance members but was looking for some other applications for
them. English is not a programming language so some variation in
interpretation (and inevitably, misunderstanding) is to be expected (on
my part that is, I can't speak for anyone else).
I actually was attempting to present a simple but useful application of
a closure. I also got the impression from Lasse's post that that was the
intention there as well. Granted that post started with some explanation
but the final examples are considerably more involved than my first
post.
I was also expecting to see more offerings in general. The subject line
of the question seeming to present a challenge. But it looks like many
of the regulars have been otherwise occupied over the last few days and
not everyone likes/uses closures (Steve actively discourages their use
for reasons that he has already mentioned (possibly among others that he
didn't)).
>An even richer response might have included a word
>or two about how closure in Javascript differs from
>that in a class-based language, if indeed such a
>difference does exist.
The relevance of closures in JavaScript to class-based languages is that
class-based (object orientated) programming likes to encapsulate some
data and methods within objects in a way that prevents it from being
manipulated (or control how it is manipulated) by external (to the
object) code. Broadly termed 'private' members.
JavaScript is an incredibly plastic language with almost everything
apparently open to manipulation and modification at all times. It
appears to be a common belief that JavaScript objects cannot have
private members (variables/fields or methods) and also that, for that
reason, JavaScript cannot be considered a true Object Orientated
language.
Douglas Crockford has demonstrated that closures can be used to provide
JavaScript objects with private members:-
<URL: http://www.crockford.com/javascript/private.html >
(That is a 'must read' page for OO JavaScript authors and very relevant
to the application of closures, but everything Douglas has to say about
JavaScript is worth reading <URL: http://www.crockford.com/#javascript >
particularly the material on inheritance (the other OO concern)).
Douglas describes how the invocation of the constructor forms a closure
that allows all of the parameters, local variables and any functions
defined as - function fncName(){ . . . ); - within the constructor to
remain associated with the object that is constructed as its private
members. And how inner functions assigned to properties of the object
instance (with - this.methodName = function(){ . . .}; -) become
'privileged' methods. Privileged because they have direct access to the
private members of the object. Apart from invoking the privileged
instance members of an object, there is no way that external code can
access the private members of the object instance. Public members are
assigned to the constructor's prototype object in the traditional way
(but public methods have no direct access to the instance's private
members).
Public and private are terms directly from class based languages (joined
by 'package' and 'protected' in Java), privileged is a term that I think
Douglas coined to describe the special role of the constructor's inner
functions assigned to externally accessible instance members.
The effect is to provide sufficient data encapsulation to remove that
argument against JavaScript being an Object Orientated language.
<snip>
>... there could have been a bit
>more of a walk before the run here.
Along with inheritance, closure is probably the most complex aspect of
JavaScript, it might just be that you have to be running to start with.
Leaving the Object Orientated application of closures for a minute and
returning to Lassie's final examples. They may seem simple but crank the
complexity up a bit and start to apply the functions to each other (and
maybe recursively) and the possibilities for wonderfully elegant
solutions to complex problems is limited only by your ability to
conceive them. But that is a long way from easy.
Still, as we are on our feet, how about some more applications of
closures?
I wrote the following as an academic exercise to experiment with using
an inner function in a constructor as a constructor for an object that
could be returned and act as an interface to the object (instance) in
which it was created.
The code is part of a JavaScript implementation of the Java Hashtable
Class. The last thing that JavaScript actually needs is another
Hashtable but my interest was in re-producing the Java Hashtable's
ability to return objects that implement the Java Enumeration Class. The
Hashtable objects have an interface in the form of their public (and
privileged) methods but the Enumeration object's interface to the
Hashtable instance needs to have features of its own. For a start there
can be many Enumerations of the same Hashtable instance active at once,
they can be enumerating either keys or values and they can all be at a
different stage in their enumeration.
The Enumeration must be an object as each Enumeration must track its own
internal state but, being constructed with a private instance member of
a Hashtable Object, it also has direct access to the other private
instance members of the Hashtable instance (the ones that actually hold
the key/value pairs for the Hashtable). Also, because each Hashtable
instance keeps a reference to itself in a private member (var self =
this;), each Enumeration can call public (and privileged) methods on the
Hashtable instance with which it is associated.
The full (and commented) code can be found at:-
<URL:
http://groups.google.com/groups?selm=b685dt%248u5%241%40hercules.btinter
net.com >
function Hashtable(){ //class constructor
//Hashtable private instance members.
var keysToIndex = {__indexToValue:[],__indexToKeys:[]};
var activeEnum = [];
var tableLength = 0;
var self = this;
//inner class constructor which is also a
//private instance method of a Hashtable instance.
function Enumeration(arrNm){
var lastIndex = null; //inner class private instance member.
var enumIndex = 0; //inner class private instance member.
while(typeof activeEnum[enumIndex] == 'number')enumIndex += 1;
activeEnum[enumIndex] = 0;
//inner class privileged instance methods.
this.hasMoreElements = function(){
if(activeEnum[enumIndex] < tableLength){
return true;
}else{
if(typeof activeEnum[enumIndex] == 'number'){
activeEnum[enumIndex] = null;
}
return false;
}
};
this.nextElement = function(){
if(this.hasMoreElements){
lastIndex = activeEnum[enumIndex];
return keysToIndex[arrNm][activeEnum[enumIndex]++];
}else{
return null;
}
};
this.remove = function(){
if(typeof lastIndex == 'number'){
self.remove(keysToIndex.__indexToKeys[lastIndex]);
lastIndex = null;
}
};
};
//Hashtable privileged instance methods
this.get = function(key){
if(typeof keysToIndex[key] == 'number'){
return keysToIndex.__indexToValue[keysToIndex[key]];
}else{
return null;
}
};
this.put = function(key, value){
if(typeof keysToIndex[key] == 'number'){
keysToIndex.__indexToValue[keysToIndex[key]] = value;
}else{
keysToIndex[key] = tableLength;
keysToIndex.__indexToValue[tableLength] = value;
keysToIndex.__indexToKeys[tableLength++] = key;
}
};
this.remove = function(key){
var remIndex = keysToIndex[key];
if(typeof remIndex == 'number'){
delete keysToIndex[key];
tableLength -= 1;
for(var c = remIndex;c < tableLength;c++){
keysToIndex.__indexToValue[c] =
keysToIndex.__indexToValue[c+1];
keysToIndex[(keysToIndex.__indexToKeys[c] =
keysToIndex.__indexToKeys[c+1])] = c;
}
for(var c = 0;c < activeEnum.length;c++){
if((activeEnum[c])&&(remIndex < activeEnum[c])){
activeEnum[c] -= 1;
}
}
}
};
this.__enumerate = function(type){
return new Enumeration(type);
};
}
//Hashtable public instance methods
Hashtable.prototype.elements = function(){
return this.__enumerate('__indexToValue');
}
Hashtable.prototype.keys = function(){
return this.__enumerate('__indexToKeys');
}
This JavaScript Hashtable illustrates all of the closure based
encapsulation features described by Douglas Crockford. You may notice,
for example, that the key/value pair data is held in a private instance
member and as a result is only accessible via that privileged get, put
and remove methods of the Hashtable instance and the privileged remove
method of its Enumerations (which calls the instance remove method
anyway). Also, as an attempt to parallel a Class from a class based
language (Java), it is quite a good basis for the comparison of this
aspect of the OO abilities of JavaScript.
Now for something a bit speculative. Speculative because I only realised
that this was possible last Tuesday and I have not really tested it yet.
The fact that I have never seen it used or heard anyone mention the
possibility is probably an indicator that there is a fatal technical
flaw in the idea that I have not yet encountered and no one has
mentioned. However . . .
In Java the modifiers private, public, package and protected can be
combined with additional modifiers, one of which is static. A member
that is static is a member of the Class and not the instance. There is
only one copy of the member per Class. In JavaScript static members are
defined as properties of the constructor:
function MyObject(){
// constructor function
}
MyObject.staticMember = 'any primitive value, object or function';
JavaScript static members defined as properties of the constructor
object are public static members. But a class might want private static
members. Private instance members are achieved by forming a closure when
objects are instantiated. It should be possible to form a closure that
included the class constructor and local variables that would server as
private class members by making a one-off function call that returned
the constructor (there is only one constructor pre class).
var myObject = global.myObject = function(){
var counter = 0; //private static (class) member
function incrementCounter(){ //private static (class) method.
return counter++;
};
function constructor(id){ //class constructor.
this.id = id;
var self = this;
//call private static (class) method and assign the returned
//index to a private instance member.
var index = incrementCounter();
this.getIndex = function(){ //privileged instance method.
return index;
};
};
//privileged static (class) method (a property of the constructor)
constructor.getNoOfInsts = function(){
return counter;
};
return constructor; //return the constructor.
}(); //simultaneously define and call (one-off)!
myObject.pubStatic = 'anything' //public static (class) member
myObject.prototype.pubInstVar = 8; //public instance member
Having the one-off function call return the class constructor forms a
closure that can hold private static members and assign privileged
static methods (as properties of the returned constructor. This is
essentially taking Douglas Crockford's method for creating private
instance members and applying it to the constructor itself to produce
the same effect at the class level.
There is an interesting side effect in that privileged instance methods
become doubly privileged in that they also have direct access to the
private static members of the class.
Apart from providing a repository for private class members, a closure
formed in this way will also provide a mechanism by which and instance
of a class can know if another instance is of the same class or not. Any
object or (more likely) function defined as a private member of the
class will be both unique and inaccessible to other classes. All an
instance of a class must do to identify a call to one of its privileged
methods as originating from an instance of the same class is to require
that the call to the method is accompanied by a reference to a private
class object or function member and compare that reference with the
correct unique private member of its own class.
The following class uses a private static 'UiD' object (in the absence
of any private static methods) as the basis for comparison. Any code can
call the getRestricted and setRestricted methods of an instance of the
class but only an instance of the same class can provide the reference
to UiD that those functions will compare with the UiD in there own class
before acting. (As the constructor is exported it (and any methods it
may be assigned) is the only object that could not be used for this
purpose.)
var MyObject = function(){
var UiD = {};
function constructor(id){ //class constructor.
var classRestricted = {};
this.id = id;
var self = this;
//privileged instance methods.
this.getRestricted = function(key, classUiD){
if(classUiD == UiD){
return classRestricted[key];
}
};
this.setRestricted = function(key, value, classUiD){
if(classUiD == UiD){
classRestricted[key] = value;
}
};
this.getFromOther = function(obj, key){
if(obj.getRestricted){
return obj.getRestricted(key, UiD);
}
};
this.setOnOther = function(obj, key, value){
if(obj.setRestricted){
return obj.setRestricted(key, value, UiD);
}
};
};
return constructor; //return the constructor.
}(); //simultaneously define and call!
The ability to restrict access to the members of an instance to only
instances of the same class is a move towards some of the access
restrictions found in class based programming languages.
Having taken the Idea that made private instance members possible and
applied it at a level that makes private static members possible the
obvious next step is to apply the same method to groups of classes. Up
to this point I have at least superficially tested the code presented.
From here on it is totally theoretical and untested.
In class based languages a grouping of classes might be a package. I
don't think that I will use package to describe groupings of classes in
Javascript. For one thing package members (private or otherwise) don't
really exist, and for another, the recursive application of the
principal allows for groupings of groupings of classes (and so on). In
all, an unusual hierarchy of nested accessibility.
As any grouping of classes would allow for 'private grouping members',
the same technique as I have just used to allow only instances of the
same class to influence each other could also be implemented at the
grouping level, allowing access to some objects internal members to only
be available to classes in the same group.
A hypothetical class grouping closure (anonymous in this case) might go
like:-
var global = this;
(function(){
var PiD = function(){
...
};
global.MyObject1 = function(){
var UiD = {};
function constructor(id){
...
};
return constructor; //return the constructor.
}(); //simultaneously define and call!
global.MyObject2 = function(){
var UiD = {};
function constructor(id){
...
};
return constructor; //return the constructor.
}(); //simultaneously define and call!
global.MyObject3 = function(){
var UiD = {};
function constructor(id){
...
};
return constructor; //return the constructor.
}(); //simultaneously define and call!
})();
So, a question for anyone who has read to the end and might know of a
problem with this. Apart from the obvious fact that JavaScript for web
pages just doesn't need to be this complex, what is the catch?
Richard.
> Reading the OP, my impression was that the question was from someone who
> knew what a closure was and understood their application in creating
> private instance members but was looking for some other applications for
> them.
Apart from the object oriented perspective, I happen to use closures
with programs involving:
- DOM events, for the reasons you have exposed
- "parallelism" between js objects and their HTML counterparts
...therefore, nothing which cannot be achieved by regular expando
properties.
> JavaScript static members defined as properties of the constructor
> object are public static members. But a class might want private static
> members. Private instance members are achieved by forming a closure when
> objects are instantiated. It should be possible to form a closure that
> included the class constructor and local variables that would server as
> private class members by making a one-off function call that returned
> the constructor (there is only one constructor pre class).
If I had needed private 'static' members I would have investigated the
opportunity to create them on the prototype, with getters/setters
using 'instanceof' to control access - the solution that you provide
is however better, and I don't really recollect having used a
constructor to return another constructor - I'll keep that at hand.
> Having taken the Idea that made private instance members possible and
> applied it at a level that makes private static members possible the
> obvious next step is to apply the same method to groups of classes.
:-)
> So, a question for anyone who has read to the end and might know of a
> problem with this. Apart from the obvious fact that JavaScript for web
> pages just doesn't need to be this complex, what is the catch?
Well, closures implementation should not be a problem, even though
specifications are quite permissive - so using closures in design
should be fine (memory issues raised by Mr Van Dongen of course apply,
but circular references also exist outside closures, if I may say:-)
).
FWIW: originally I would have said that js privileged design
flexibility, and that the mix of closures/objects, while offering
great opportunities for neat local coding, would not have given a
solid framework for conception, but the more time goes by, the more I
learn about programming, the more I feel there's no catch at all, it's
just a matter of well-organized host... I suspect that jseng regulars
might have more to say on the whole story.
Inspiring post BTW :-)
Regards,
Yep.
Below is another example of the use of closure. It may have some
resonance with those who have struggled with the environment for
"window.setTimeout" or "window.setInterval", where often global
variables are resorted to in order to maintain some state. Note that
this example bears a good deal of similarity to the example found in
Douglas Crockford's paper:
http://www.crockford.com/javascript/private.html
(which Richard Cornford recently provided a reminder of the valuable
information to be found there).
The idea here is to be able to set up an interval timer that fires for
the appropriate number of times, at the given rate, and then clears
itself after satisfying the call for service.
function obj(param) { // Constructor
var thisObj = this; // Copy object reference
this.name = param; // Name this object (public)
var counter, timerId; // Create private vars
this.setTimer = function(count,delay) { // Timer service function
counter = count; // Capture initial count
timerId = setInterval(intervalEvent,delay); // Capture id
}
function intervalEvent() { // Timer event handler
if (counter > 0) {
alert("intervalEvent called, counter: "+counter);
// ... Code that does something useful replaces above alert
}
else { // Counter exhausted
clearInterval(timerId); // Clear interval timer
alert("Cleared timer for "+thisObj.name); // this != thisObj
}
counter--; // Reduce iteration counter
}
}
var test = new obj('test'); // Instantiate object
test.setTimer(5,500); // Request timer service
../rh
<snip />
> this.setTimer = function(count,delay) { // Timer service function
> counter = count; // Capture initial count
> timerId = setInterval(intervalEvent,delay); // Capture id
> }
>
> function intervalEvent() { // Timer event handler
> if (counter > 0) {
> alert("intervalEvent called, counter: "+counter);
> // ... Code that does something useful replaces above alert
> }
> else { // Counter exhausted
> clearInterval(timerId); // Clear interval timer
> alert("Cleared timer for "+thisObj.name); // this != thisObj
> }
> counter--; // Reduce iteration counter
> }
> }
>
> var test = new obj('test'); // Instantiate object
> test.setTimer(5,500); // Request timer service
IE 5+ allows you to pass a function reference as the first parameter
to setTimeout/setInterval, but does anyone else support that?
Regards,
Steve
>IE 5+ allows you to pass a function reference as the first parameter
>to setTimeout/setInterval, but does anyone else support that?
Passing a function as the first parameter is OK according to Netscape's
current client side documentation (I don't know which version introduced
it but 4.70 supports it), and tested OK on Mozilla 1.0 and Opera 6.04
and 7.01.
However, I cannot see the PDA browsers that do not implement eval
supporting the string argument versions (I don't see how they could) and
there was recently a post that stated that pocket IE only supported the
string version.
Of course the general principal for cross-browser scripting is to test
the capabilities of the browser before jumping in and using them. An
interesting trick is to provide the setTimeout/Interval function with a
function reference but to also override the toString functions on the
function passed. So that it returns a string of JavaScript code that
setTimeout/Interval will accept as its first argument if it type
converts the function reference to a string (which is what happened in
testing).
However, there is a major problem with testing the setTimeout/Interval
functions in that you have to call them and it seems that neither will
actually get a chance to execute until _after_ the page onload event. So
the results are not available inline as the page loads, or within the
onload event.
For comparison, this is my testing page:-
<html>
<head>
<title>setTimeout tests</title>
<script type="text/javascript">
var setTmExists = (typeof window.setTimeout != 'undefined');
var setInExists = (typeof window.setInterval != 'undefined');
var setTmString = false;
var setTmFunc = false;
var setInString = false;
var setInFunc = false;
var testTimer;
function testSetTm(){
setTmFunc = true;
setTimeout('setTmString = true;', 1);
}
testSetTm.toString = function(){
return 'setTmString = true;';
}
function testSetIn(){
clearInterval(testTimer);
setInFunc = true;
testTimer = setInterval(
'setInString = true;clearInterval(testTimer);', 1);
}
testSetIn.toString = function(){
return 'setInString = true;clearInterval(testTimer);';
}
if(setTmExists){
setTimeout(testSetTm, 1);
}
if(setInExists){
testTimer = setInterval(testSetIn, 1);
}
function checkTest(){
var st = 'The window.setTimeout function '+
(setTmExists?'exists':'does not exist')+'\n';
if(setTmExists){
st += '\tstring arguments are '+
(setTmString?'':'not ')+'supported\n\tfunction arguments are '+
(setTmFunc?'':'not ')+'supported\n';
}
st += '\nThe window.setInterval function '+
(setInExists?'exists':'does not exist')+'\n';
if(setInExists){
st += '\tstring arguments are '+
(setInString?'':'not ')+'supported\n\tfunction arguments are '+
(setInFunc?'':'not ')+'supported\n';
}
alert(st);
}
checkTest.toString = function(){
return 'checkTest();';
}
</script>
</head>
<body>
<p>setTimeout tests.
<script type="text/javascript">
setTimeout(checkTest, 400);
</script>
</p>
</body>
</html>
Richard.
Because the function that is passed as a reference to the setInterval
function is an inner function that represents a private method of an
object, it might be possible to exploit that toString trick to have the
function called regardless of whether the setInterval function supports
the function reference or not.
In the following modified version of rh's script the added toString
function stores a reference to the inner function in a public static
Array (that it may create) and returns a string that will call that
member of the Array. The function works exactly the same as it would if
it was called via the reference in setInterval because as an inner
function it still has direct access to the private instance members that
it uses.
function obj(param) { // Constructor
var thisObj = this; // Copy object reference
this.name = param; // Name this object (public)
var counter, timerId; // Create private vars
this.setTimer = function(count,delay) { // Timer service function
counter = count; // Capture initial count
timerId = setInterval(intervalEvent,delay); // Capture id
};
function intervalEvent() { // Timer event handler
if (counter-- > 0) {
alert("intervalEvent called, counter: "+counter);
// ... Code that does something useful replaces above alert
}else{ // Counter exhausted
clearInterval(timerId); // Clear interval timer
alert("Cleared timer for "+thisObj.name);// this != thisObj
}
};
intervalEvent.toString = function(){
if(!obj.tempFunc)obj.tempFunc = [];
var c = 0;
//Note: this function is a property of a function
//so the 'this' keyword refers to that function.
while((typeof obj.tempFunc[c] != 'undefined')&&
(obj.tempFunc[c] != this)){
c++
}
if(obj.tempFunc[c] != this){
obj.tempFunc[c] = this;
}
return 'obj.tempFunc['+c+']();'
};
}
var test = new obj('test'); // Instantiate object
test.setTimer(5,500); // Request timer service
But if this was a facility that was wanted in several classes and/or
functions, and as we are writing applications for closures, how about
providing one toString function definition and using a closure to
associate it with the Constructor that contains the function to which it
is attached. So, changing the - intervalEvent.toString = - line to:-
intervalEvent.toString = setToString('obj');
- and adding the global function:-
function setToString(constName){
return function(){
if(!window[constName].tempFunc)window[constName].tempFunc = [];
var c = 0;
while((typeof window[constName].tempFunc[c] != 'undefined')&&
(window[constName].tempFunc[c] != this)){
c++
}
if(window[constName].tempFunc[c] != this){
window[constName].tempFunc[c] = this;
}
return (constName+'.tempFunc['+c+']();');
};
}
Richard.
A much more efficient version of the setToString function could go:-
function setToString(constName){
if(!window[constName].tempFunc)window[constName].tempFunc = [];
var set = false;
return function(){
if(!set){ //one time only!
var c = window[constName].tempFunc.length;
window[constName].tempFunc[c] = this;
set = true;
constName = constName+'.tempFunc['+c+']();';
}
return constName;
};
}
- as it does considerably less work on each invocation of the inner
function. However it does now assume that the reference to the function
that is stored in the public static member of the constructor is not
changed by other scripts.
Although, storing a reference to a private method of an object instance
will prevent garbage collection of the object instance (at least until
the page unloads) so the 'tempFunc' array (or the function reference
within it) might have to be actively nulled if the cyclic reference to
activeX and HTML element problem that Steve van Dongen raised is likely
to be significant.
Richard.
> - as it does considerably less work on each invocation of the inner
> function. However it does now assume that the reference to the function
> that is stored in the public static member of the constructor is not
> changed by other scripts.
>
> Although, storing a reference to a private method of an object instance
> will prevent garbage collection of the object instance (at least until
> the page unloads) so the 'tempFunc' array (or the function reference
> within it) might have to be actively nulled if the cyclic reference to
> activeX and HTML element problem that Steve van Dongen raised is likely
> to be significant.
>
> Richard.
(My version of the thread currently looks as:
\-11 Lasse Reichstein Nielsen 22 Apr 2003
\-12 Richard Cornford 27 Apr 2003
\-13 Richard Cornford 27 Apr 2003
\-14 Richard Cornford 28 Apr 2003
missing my prior post, and apparently one from Steve van Dongen, so I
may not be tracking correctly.)
Your extension here and above is interesting and instructive. Not sure
how practical or necessary it is though.
Another objection that may well arise is that you appear to have
converted private functions into a public functions (which I also did,
perhaps, by handing off the reference to setInterval -- but I
considered it trusted) by adding the accessible references to the
constructor object.
That suggests to me that intervalEvent really ought to be
this.intervalEvent, i.e., a public function to begin with, just so
everything stays clear and consistent regarding public vs. private.
With that change you should be able to store references to the primary
objects, rather than references directly to inner functions, and still
be able to get to the handler through the eval of a string generated
by the .toString invocation.
That doesn't solve the problem of creating additional references,
however.
(By the way, thanks for cleaning up the slightly brain-dead iteration
control in my example. I debated about fixing it prior to posting, but
wasn't capable at the time ;-)).
I quoted Steve van Dongen's comments on your post in full (as it was
short) so you have the full picture. I find that sometimes posts take a
couple of days to filler through to my server so hang on, they may show
up yet (though I think you should be able to see your own posts fairly
quickly).
>Your extension here and above is interesting and instructive.
>Not sure how practical or necessary it is though.
I am not sure how necessary it is either. It does make code that would
fail on IE 4 into code that works on IE 4 and it should have a similar
effect on other browsers that do not accept a function reference as the
first argument to setTimeout/Interval, assuming that they do the type
conversion and call toString to achieve it. It seems like a good way of
maximising browser compatibility while still preferring the (presumably)
more efficient function reference option. But I will still have to test
it on some other string argument only browsers to see how well it stands
up.
>Another objection that may well arise is that you appear to have
>converted private functions into a public functions ( ..)
>by adding the accessible references to the constructor object.
It may make the function public but _only_ if the toString function is
actually called. I did wonder whether that was a good idea but I decided
that it was more important to be in a position to exploit the
setTimeout/Interval functions without having to jump through hoops to
test which version of setTimeout/Interval to use, and branch the
relevant code. It is also anonymously public, it would be difficult for
an external script to work out which object's function was in which slot
in the array.
>That suggests to me that intervalEvent really ought to be
>this.intervalEvent, i.e., a public function to begin with,
>just so everything stays clear and consistent regarding public
>vs. private. With that change you should be able to store
>references to the primary objects, rather than references
>directly to inner functions, and still be able to get to the
>handler through the eval of a string generated by the .toString
>invocation.
I don't think that the possibility of making the function public (only
if toStirng is called) justifies making it a public member of the
object. The toString function would still have no way of knowing the
name of the variable that held the reference to the instance created
with - new obj('test'); - so it would still have to facilitate a
reference to the function through a public member of the constructor
(even if it did that by storing a reference to the object in the array
instead of to the function).
>That doesn't solve the problem of creating additional
>references, however.
<snip>
Addressing that issue would depend entirely on the nature of the objects
used, but I think it does need to be addressed. As your timing objects
stands the function references in the Array would prevent the object
instances from being garbage collected if the variable they where
assigned to where freed (again, maybe a task for a destroy/finalize
function to free the function references), but the object could be
re-usable (so no need to dispose of it), and it has no references
outside of the JavaScript so it should be automatically freed as the
page unloads.
Richard.
In a procedural program, I once saw the comment "Now try to find a dry
piece of mud to stand on!", as the programmer grappled with state
recovery. Obviously, closures weren't available.
Some descriptions of closure are found to be something of the form:
An object associates data with multiple methods,
where closure associates data with a method.
This perhaps sells objects a little short, and without doubt does the
same for closure. Nonetheless, it appears that if this were applied to
Javascript, it might be written as:
An object associates data with multiple methods,
as does closure.
That brings up the questions, what data, and what's the difference?
Well, it all depends on the location from which the object is viewed.
There's an outside (public) view, and an inside view, the latter being
the view from a method of the object that has been invoked. In other
words, as is not uncommon, what you see depends on where you are.
Invoking a method of the object causes a transition whereby more of
the object is exposed -- i.e, the closed (private) part is opened up
and, along with the public part, becomes accessible to the method as
it executes. The method is therefore said to be privileged with
respect to its containing object, because it can see and do more with
the object than methods which are external to the object.
The hidden data name-storage bindings and privileged methods are
established at the time an object is created -- that is, from a
privileged state. This established relationship persists with the
object, thereby not only allowing the transition upon a method call
described above, but also maintaining the integrity of private vs.
public access to the object.
What are closures good for? Well, they're all about hiding and holding
of state, which is recoverable by those who are authorized, or
privileged, to do so. The magic is, if you can get to the method, the
method can get to the state.
(Some will recall that the Beatles sang "Get back. Get back. Get back
to where you once belonged". We don't know what happened to good-old
Jojo, but a closure would likely have come in rather handy if it was
important that the imperative be satisfied. ;-^))
../rh
My thoughts until Jim raised the potential problems with Java based
browsers. But I still haven't tested how significant his concerns
actually are.
<snip>
>If I had needed private 'static' members ...
<snip>
JavaScript objects will happily get by with exclusively public instance
and static members and the risks of accidental interactions causing
problems are not too great as JavaScript systems are usually not large
or complicated and no one is insane enough to write aeroplane
auto-pilots and the like with it.
So there is no *need* for private members (static or otherwise). There
is an OO dogma that if a member can be private it should be private, and
that should go for classes as well as instances. That would make the
question: does a class member need to be public? And usually they don't.
Making class members private should have no extra cost in terms of
memory use, just the restriction that only private and 'privileged'
methods would have access to them.
On the other hand, implementing the mechanism for restricting the use of
methods to just instances of the same class (or class group) is not
something that I can see myself ever wanting to do. Mostly because of
the overhead, but it is nice to know that it can be done.
>Well, closures implementation should not be a problem, ...
<snip>
>... (memory issues raised by Mr Van Dongen of course apply, but
> circular references also exist outside closures, if I may say:-)
That is a good point, assigning a reference to an object instance to an
added property of an HTML element while the object holds a reference to
the element is just a circular. More reason for building objects with an
automated destroy/finalize mechanism. Something to look at tomorrow.
<snip>
>... I suspect that jseng regulars
>might have more to say on the whole story.
Nothing yet, again, but not objections to the idea.
>Inspiring post BTW :-)
I was feeling inspired when it occurred to me how to go about creating
static members, and afterwards thinking about how far the idea could be
taken. I posted it to see if anyone knew of a problem (and as we where
on the subject). Now I suppose I will have to come up with an
application that really exploits the possibilities that it offers.
Thanks for the positive comments (and posting all of those examples of
closure applications that have been nudging me in this direction over
the last months. :-)
Richard.
var TimedQue = function(){
var base, timer;
var interval = 40;
var newFncs = null;
function addFnc(next, f){
function t(){
next = next&&next();
if(f()){
return arguments.callee;
}else{
f = null;
return next;
}
};
t.addItem = function(d){
if(next){
next.addItem(d);
}else{
next = d;
}
return this;
};
t.finalize = function(){
return ((next)&&(next = next.finalize())||(f = null));
};
return t;
};
function tmQue(f){
if(newFncs){
newFncs = newFncs.addItem(addFnc(null, f));
}else{
newFncs = addFnc(null, f);
}
if(!timer){
timer = setTimeout(tmQue.act, interval);
}
};
tmQue.act = function(){
var f = newFncs, strt = new Date().getTime();
if(f){
newFncs = null;
if(base){
base.addItem(f);
}else{
base = f;
}
}
base = base&&base();
if(base){
var t = interval - (new Date().getTime() - strt);
timer = setTimeout(tmQue.act, ((t > 0)?t:1));
}else{
timer = null;
};
};
tmQue.act.toString = function(){
return 'TimedQue.act()';
};
tmQue.finalize = function(){
timer = clearTimeout(timer);
base = base&&base.finalize();
slotIndex = 0;
newFncs = [];
};
return tmQue;
}();
To avoid Steve van Dongen's circular reference problem I have included a
finalize function to free all of the function references. That function
would need to be called onunload, so...
<snip>
>>That doesn't solve the problem of creating additional
>>references, however.
<snip>
>..., maybe a task for a destroy/finalize
>function to free the function references...
What is needed is a general mechanism for adding any finalize methods
(private or public, static or instance) to the window.onunload event.
This closure has a go at that using a very similar queue to the example
above. Called as - finalizeMe(fn); - it will arrange that fn is called
onunload (if the same function is already queued it will not be added).
finalizeMe.remove(fn) - will remove the function from the queue (and is
harmless if the function is not in the queue).
var global = this;
var finalizeMe = function(){
var base;
var safe = false;
var svType = (global.addEventListener && 2)||
(global.attachEvent && 1)|| 0;
function addFnc(next, f){
function t(ev){
if(next)next(ev);
f(ev);
};
t.addItem = function(d){
if(f != d.getFunc()){ //don't add duplicates!
if(next){
next.addItem(d);
}else{
next = d;
}
}
return this;
};
t.remove = function(d){
if(f == d){
f = null;
return next;
}else if(next){
next = next.remove(d);
}
return this;
};
t.getFunc = function(){return f;};
t.finalize = function(){
if(next)next = next.finalize();
return (f = null);
};
return t;
};
function addFunction(f){
if(base){
base = base.addItem(addFnc(null, f));
}else{
base = addFnc(null, f);
}
};
function ulQue(f){
addFunction(f);
if(!safe){
switch(svType){
case 1:
global.attachEvent("onunload", base);
safe = true;
break;
case 2:
global.addEventListener("unload", base, false);
safe = true;
break;
default:
if(global.onunload != base){
if(global.onunload)addFunction(global.onunload);
global.onunload = base;
}
break;
}
}
};
ulQue.remove = function(f){
if(base)base.remove(f);
};
function finalize(){
if(base){
base.finalize();
switch(svType){
case 1:
global.detachEvent("onunload", base);
break;
case 2:
global.removeEventListener("unload", base, false);
break;
default:
global.onunload = null;
break;
}
base = null;
}
safe = false;
};
ulQue(finalize);
return ulQue;
}();
The only problem that I have seen with this function to date is that on
Mozilla (Gecko) browsers an onunload event specified in the HTML body
tag will not get executed if addEventListener is used to listen to
unload events.
Richard.
>Yep wrote in message ...
><snip>
>>Apart from the object oriented perspective, I happen to use
>>closures with programs involving:
>>- DOM events, for the reasons you have exposed
>>- "parallelism" between js objects and their HTML counterparts
>>
>>...therefore, nothing which cannot be achieved by regular
>>expando properties.
>
>
>My thoughts until Jim raised the potential problems with Java based
>browsers. But I still haven't tested how significant his concerns
>actually are.
I only know of it in Batik's Squiggle (which is an SVG viewer, not, an
HTML one) it's also relatively easy to implement if using Rhino , so I
don't think it's a major concern, the Batik people unfortunately did a
static implementation first - no javascript - so changing all the Node
types to inherit from the js objects was more effort.
Jim.
--
comp.lang.javascript FAQ - http://jibbering.com/faq/
At the time you also mentioned Ice Storm as potentially having a
problem. I have recently been testing IceBrowser 5.4.1 (looks like they
have dropped Ice Storm as a name) and have confirmed that it mostly does
not have a problem with letting JavaScript add properties to its DOM
elements. It does follow IE in creating attribute elements for any
properties added to a DOM element with JavaScript.
I did find two objects that would not allow properties to be added with
JavaScript and in both cases the result of attempting to do so was to
crash the browser (tested within try/catch so it was not just an
uncaught exception). The first was - document.selection - which is not a
big problem as there is no good reason to be adding properties to that
object. The other was the object referenced with - defaultView - . On
gecko browsers the defaultView property is a reference to a window
object, therefor a global object to which properties can be added. On
IceBrowser 5 - defaultView - is a very different object, containing what
are clearly Java methods and objects (e.g. class, notifyAll, hashCode,
wait, etc.).
Richard.