Closures?

L

Leo Meyer

Hello,

somewhere I have read that JavaScript supports closures. Does someone know
how to make them work?

What I want to do is this:

function f1(x, obj) {

var eventhandler = function(event) {
someobject.somevalue = x;
}
// set event handler
obj.onclick = eventhandler;
}

When the event handler is being called, the value of x at the time of the
call of f1 should be used. Unfortunately, this doesn't work; the value is
always 'undefined'. JavaScript probably tries to access the global variable
'x' which does not exist outside of f1's context.

I have tried a workaround:

function f1(x) {
var eventhandler = function(event) {
someobject.somevalue = this.x;
}
eventhandler.x = x;
// set event handler
obj.onclick = eventhandler;
}

This works in newer browsers (Firefox 1.5, IE 7). But not in IE 6; it seems
that anonymous functions can't have properties in IE 6's implementation :-(

Is there an elegant solution? I wouldn't want to use something like:

var fntext = "someobject.somevalue = " + x + ";";
var eventhandler = new Function("event", fntext);

because I find this hard to read and debug, especially if there are special
characters in the function body that need to be escaped.

Thanks for suggestions,

Leo
 
R

RobG

Leo said:
Hello,

somewhere I have read that JavaScript supports closures. Does someone know
how to make them work?

Try this article that can be found from the FAQ, though not easily:

<URL: http://www.jibbering.com/faq/faq_notes/closures.html >

Are you sure you need closures? Can you do the same thing with plain
old object properties?
What I want to do is this:

function f1(x, obj) {

var eventhandler = function(event) {
someobject.somevalue = x;
}
// set event handler
obj.onclick = eventhandler;
}

When the event handler is being called, the value of x at the time of the
call of f1 should be used. Unfortunately, this doesn't work; the value is
always 'undefined'. JavaScript probably tries to access the global variable
'x' which does not exist outside of f1's context.
[...]

Try this one:

<script type="text/javascript">

var objA = (function(){
var x;
return {
setX : function(val){ // Function to set value of x
x = val;
},
addClick : function(el){
el.onclick = function(){
alert('Value is: ' + x); // Closure to local x
}
}
}
})();

window.onload = function(){
objA.addClick(document.getElementById('button0'))
objA.addClick(document.getElementById('button1'))
}

</script>
<body>

<button id="button0">Button 0</button>
<button id="button1">Button 1</button>
<br><br><br>
<input id="inp0" value="10">
<button
onclick="objA.setX(document.getElementById('inp0').value);">Set
This works in newer browsers (Firefox 1.5, IE 7). But not in IE 6; it seems
that anonymous functions can't have properties in IE 6's implementation :-(

They certainly can, but you don't want (public) properties, you want
the equivalent of private members.

Is there an elegant solution? I wouldn't want to use something like:

var fntext = "someobject.somevalue = " + x + ";";
var eventhandler = new Function("event", fntext);

I don't think I understand what you want here...
 
L

Leo Meyer

Try this article that can be found from the FAQ, though not easily:

Thanks for the link. Excellent read.
Are you sure you need closures? Can you do the same thing with plain
old object properties?

aka "poops"? no thanks ;-)

Joke aside, the code from the original post works. I guess I made a mistake
somewhere else, as my "real" code is a bit more involved than the example I
posted.
They certainly can, but you don't want (public) properties, you want
the equivalent of private members.

Accessibility isn't an issue in my situation. Concerning properties of
anonymous functions, the following code works in neither browser I have
tried:

<script type="text/javascript">
function f1(x, obj) {
var eventhandler = function(event) {
alert(this.x);
};
eventhandler.x = x;
// set event handler
obj.onclick = eventhandler;
}
window.onload=function(){
f1(5, document.getElementById("theA"));
f1(6, document.getElementById("theB"));
}
</script>
<a id="theA" href="#">theA produces 5</a><br>
I don't think I understand what you want here...
I don't want it ;-) This is a very clumsy way to create a function.

Thanks & regards,
Leo
 
M

Michael Winter

Leo Meyer wrote:

[snip]
Joke aside, the code from the original post works.

Good. I was going to ask for a link to a demonstration because it
certainly should have.

[snip]
var eventhandler = function(event) {
alert(this.x);
};
eventhandler.x = x;
// set event handler
obj.onclick = eventhandler;

You assign the value to a property of the function object, and then
expect to get it back using the this operator. The only way that could
happen is if the this operator referred to the function object, and
that's unlikely to occur unless the Function.prototype.apply or call
methods are used:

function myFunction() {
alert(this.property);
}
myFunction.property = 'value';

myFunction.call(myFunction);

or the function is called via another property that refers to the object:

function myFunction() {
alert(this.property);
}
myFunction.me = myFunction;
myFunction.property = 'value';

myFunction.me();

I think you'll agree that both are quite unlikely.

If the function was called directly, the this operator would refer to
the global object, so you would be looking for a property on the wrong
object. As it is, the function in your code is added as an event
listener. When the relevant event reaches that target (the element), the
function will be called as its method and the this operator will refer
to that element - you'd still be looking in the wrong place.

Mike
 
L

Leo Meyer

You assign the value to a property of the function object, and then expect
to get it back using the this operator. The only way that could happen is
if the this operator referred to the function object, and that's unlikely
to occur unless the Function.prototype.apply or call methods are used:

OK. I thought that "var eventhandler = function(event) {...}" created a new
function object, and that functions are called with the this operator set to
the function object. I see now that this is not necessarily the case.
If the function was called directly, the this operator would refer to the
global object, so you would be looking for a property on the wrong object.
As it is, the function in your code is added as an event listener. When
the relevant event reaches that target (the element), the function will be
called as its method and the this operator will refer to that element -
you'd still be looking in the wrong place.

Interesting. I've still got much to learn about JS.

Thanks and regards,
Leo
 
M

Michael Winter

Leo Meyer wrote:

[snip]
I thought that "var eventhandler = function(event) {...}" created a
new function object,

If it's evaluated, it will.
and that functions are called with the this operator set to the
function object.

The value of the this operator is determined by /how/ the function is
called. You can find discussions of this topic in the Google Groups
archives[1] as it's a fairly frequently discussed issue.

Be aware that the poster using the pseudonym "VK" thinks he understands
this topic, and you'll find him rambling on about it often. Ignore
everything he writes: he hasn't the faintest clue.

[snip]
Thanks and regards,

You're welcome.
Mike


[1] (en) <http://groups.google.co.uk/group/comp.lang.javascript?hl=en>
(de) <http://groups.google.de/group/comp.lang.javascript?hl=de>
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top