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? :)
>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? :)
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. ...
Svend Tofte <svendto...@svendtofte.com> writes: Svend Tofte <svendto...@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.'
"Richard Cornford" <Rich...@litotes.demon.co.uk> wrote in message <news:b843v5$lfi$1$8302bc10@news.demon.co.uk>... > Svend Tofte wrote in message > <8d54528badb2f585a37b76c4c3e19...@news.teranews.com>... > >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? :)
> 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. > ... > }
> 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.
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);}; ...
>"Richard Cornford" <Rich...@litotes.demon.co.uk> wrote in message <news:b843v5$lfi$1$8302bc10@news.demon.co.uk>... >> Svend Tofte wrote in message >> <8d54528badb2f585a37b76c4c3e19...@news.teranews.com>... >> >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? :)
>> 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. >> ... >> }
>> 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.
>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?
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.
rh wrote in message <290e65a0.0304231822.2252d...@posting.google.com>...
<snip>
>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?
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.
> On 23 Apr 2003 20:02:24 -0700, codeHan...@yahoo.ca (rh) wrote:
> >"Richard Cornford" <Rich...@litotes.demon.co.uk> wrote in message <news:b843v5$lfi$1$8302bc10@news.demon.co.uk>... > >> Svend Tofte wrote in message > >> <8d54528badb2f585a37b76c4c3e19...@news.teranews.com>... > >> >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? :)
> >> 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. > >> ... > >> }
> >> 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.
> >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?
> First, what is "e"? I think you meant > txtEl.onchange = function() {o.doOnChange(txtEl);};
"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 :-).
>.... 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.
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:-
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.
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 Cornford" <Rich...@litotes.demon.co.uk> wrote in message <news:b88qbm$7jd$1$8300dec7@news.demon.co.uk>... > rh wrote in message <290e65a0.0304231822.2252d...@posting.google.com>... > <snip> > >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?
> Either approach will be functional, whether one is simpler that the > other would depend on the bigger context.
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.
>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.
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 wrote in message <290e65a0.0304250911.6a7b8...@posting.google.com>...
<snip>
>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).
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:-
(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.
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
...
"Richard Cornford" <Rich...@litotes.demon.co.uk> wrote in message <news:b8dshd$d46$1$8302bc10@news.demon.co.uk>... > 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.
> > 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? :)
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:
(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
>> timerId = setInterval(intervalEvent,delay); // Capture id >> }
>> function intervalEvent() { // Timer event handler
<snip>
>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);
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);
>... 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).
<snip>
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+']();'); };
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.
> - 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 ;-)).
rh wrote in message <290e65a0.0304281530.c02e...@posting.google.com>...
<snip>
>missing my prior post, and apparently one from Steve van Dongen, >so I may not be tracking correctly.)
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.
Svend Tofte <svendto...@svendtofte.com> wrote in message <news:8d54528badb2f585a37b76c4c3e19694@news.teranews.com>... > 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? :)
> Regards, > Svend
> (new to comp.lang.javascript!)
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. ;-^))
>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.
<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. :-)
Another closure offering! I envision this function as a centralised scheduling function for DHTML animation effects. A reference to a function that does the animation (including a private instance method) is passed to the TimedQue function and is placed in a queue. All of the functions in the queue are executed at 40 millisecond intervals (or as closes as practical). The functions are required to provide a return value of - true - if they want to stay in the queue.
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.
On Wed, 30 Apr 2003 02:16:43 +0100, "Richard Cornford"
<Rich...@litotes.demon.co.uk> wrote: >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.
>>>...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.
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.).