08 June, 2009

arguments.callee

ECMAScript 5 strict mode has completely removed arguments.callee.

Now, there have been very good arguments both for and against arguments.callee, and I'm not going to go into them. However, what I will go into is how it changed my coding style, and also some possible perks.

Let's take an example of code that I showed in an earlier post:

var alert = function () {
    var that = arguments.callee;
    if (!that.stop) {
        that.stop = !confirm(Array.prototype.join.call(arguments, "\n"));
    }
};

Now, there isn't anything particularly wrong with this code: it works fine, and passes JSLint. However, it will surely fail in strict mode. Here is how I corrected it:

var alert = function anon() {
    if (!anon.stop) {
        anon.stop = !confirm(Array.prototype.join.call(arguments, "\n"));
    }
};

The above does the same thing, but without using arguments.callee. How is this possible? It uses a named anonymous function. Yes, yes, it's an oxymoron, but please bear with me here.

Most anonymous functions are.. well, anonymous. If you want to do any kind of recursion, you have to either name the function (polluting the namespace), or use arguments.callee.

However, in later versions of ECMAScript, we are given the ability to make a named anonymous function. This is like a combination between a named function and an anonymous function, but with a twist: the name is only usable inside of the function.

Let's test that with some code:

var foo = function bar() {
    alert(bar);
    alert(window.bar === bar);
};
foo();

Note how the anonymous function bar() is accessible within itself, but does not create a global function bar(). In addition, if we assigned this function to a different variable, bar() would still be intact!

Using this technique, we no longer have any need for arguments.callee. We can use bar() within the function to refer to itself, and nothing outside has access to bar().

An interesting side effect of this is that alert.stop is undefined. In the old way you could access alert.stop. That turned out to be harmless; but in a more critical function it could have had disastrous effects.

The primary argument against this change is that it breaks stuff in IE. Except that IE has always had severe problems. It should work just fine in any non-IE browser. Also note that this only matters if you are using strict mode. If you are in normal non-strict mode, you can still use arguments.callee.

Either way, I plan to use this technique much more often, as it has proven it's use.

No comments:

Post a Comment