Anonymous function quick tips

Anonymous functions are those functions that you declare "on-the-fly" in your ECMAScript code. For example:

setTimeout(function() { alert('hey there!'); }, 2000);

Notice how the function that is being passed to setTimeout(..) is declared on the spot, at the very moment we need it. There isn't necessarily anything wrong with doing this, and sometimes it can be quite useful indeed.

There is something you need to watch out for though, and it's pretty important: using lambda functions as event handlers.

Because some popular web browsers have flawed implementations of ECMAScript (IE in particular), there is always a possibility that the code you write may end up causing memory leaks. One common way that memory can sometimes leak in IE is when a programmer fails to call .detachEvent(..) on a DOM object that previously had an event handler attached. For example:

// assume myDiv is a valid DOM object reference
myDiv.attachEvent('onclick', sayHello);

function sayHello()
alert('hey there!');

Given the code above, if the programmer never makes a call to myDiv.detachEvent('onclick', sayHello);, then this script is ripe with potential to leak memory. In other words, when the page unloads (i.e. the user browses to a different site), the browser might never let go of the memory it allocated when attaching the event. It should mind you. That it doesn't, is definitely a browser flaw, but still… the burden is on us programmers to clean up the mess.

What does any of this have to do with anonymous functions? Well, it turns out that anonymous functions can't be detached, ever! That's right; if you call .attachEvent(..) passing in an anonymous function, you'll never be able to detach it. People often have a hard time believing this and are tempted to try the following:

myDiv.attachEvent('onclick', function() { alert('HI!'); });
myDiv.detachEvent('onclick', function() { alert('HI!'); });

This accomplishes a whole lot of nothing, except perhaps to demonstrate that you don't really understand ECMAScript. Since the function keywords indicates the declaration of a brand new function, you're not doing anything when you call .detachEvent(..) while passing in an anonymous function. Rather, you're trying to detach a function that you just created on the spot, which was never attached in the first place! How could it have been? You just created it.

The easiest way to handle this situation then, is to stuff your function in a variable. Then it is trivial to attach and detach it as you please.

var fn = function() { alert('hey there!'); };

myDiv.attachEvent('onclick', fn);
myDiv.detachEvent('onclick', fn);

Of course, you don't have to stuff your function in a variable the way I did above. You can declare your function in the more traditional way: function fn() { ... }, and that will work just fine too.

Either way, I trust you get the idea. So there you go. A nice, short blog entry with a quick-tip about dealing with anonymous functions.

Comments welcome.

3 thoughts on “Anonymous function quick tips”

  1. You are right, Stephen. Some believe that the anonymous functions are identical ( resolved invalid bug).

    What about IE behaviour when 1 function == 2 different objects (FunctionDeclaration in love with FunctionExpression) ?

    var fn1 = function fn2() { alert('hey there!'); };
    function att() { myDiv.attachEvent('onclick', fn1); }
    function det() { myDiv.detachEvent('onclick', fn2); }

    p.s. Wonderful blog!

  2. Zeroglif:

    That's interesting. It looks like Mozilla balks at the syntax of something like:

    var fn1 = function fn2() { … }

    IE accepts this, but does not see fn1 as being equal to fn2 and therefore, any attempt to remove the listener by calling .detach('onclick', fn2) fails.

    Both IE and Mozilla however, are happy with something like this:

    var fn1, fn2;
    fn1 = fn2 = function() { … }

    In that case, fn1 and fn2 are equal to each other and the event listener removal should succeed.

Leave a Reply

Your email address will not be published. Required fields are marked *