What’s In a Name?
As a stickler for semantics (some might call me a curmudgeon) one of the most amusing concepts I’ve come across in messing with functional programming and recursion in Javascript is the named anonymous function.
Of course, functions in Javascript are first-class citizens, so creating anonymous functions is trivial. But for those cases when an anonymous function needs to call itself recursively, Javascript provided a back door. It was a less-than-elegant solution, and it is being deprecated with ECMAScript 5.
The Old Way: arguments.callee
Older versions of Javascript supported an arguments.callee property on functions. This allowed an anonymous function to reference itself for purposes such as recursion.
For example, this self-executing anonymous function inside an alert returns the recursively-generated factorial of the argument passed in:
alert( (function(n) { if (n<=1) { return 1; } else { return n * arguments.callee(n-1); } })(5) ); //120
If you try to run this in strict mode in an ECMAScript 5 environment, the browser will complain:
alert( (function(n) { "use strict"; if (n<=1) { return 1; } else { return n * arguments.callee(n-1); } })(5) ); //TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
The New Way: Named Anonymous Functions
By using a named anonymous function–and yes, that concept blew my mind when I learned about it, too–you can create a reference to the function call that is only recognized within the scope of the function. This will provide the same access that arguments.callee used to provide:
alert( (function factorial(n) { "use strict"; if (n<=1) { return 1; } else { return n * factorial(n-1); } })(5) ); //120
Managing Scope
Note that the new named function defined while creating this anonymous function is not accessible outside the scope of the function itself. It is as transient as the original unnamed anonymous function was. If you try to call it after the function has exited, you will get an undefined function error:
alert( (function factorial(n) { "use strict"; if (n<=1) { return 1; } else { return n * factorial(n-1); } })(5) + factorial(6); ); //ReferenceError: factorial is not defined