Hello, I'm Nick Fitzgerald. This is my weblog. You can also check out my shared items from Reader and code on GitHub. Feel free to contact me about whatever.
June 2nd, 2010
There is a fairly well known method anonymous recursion in Javascript. Every
Javascript function has access to an implicit arguments object,
and attached to that is the the callee property which holds the
function being currently being invoked.
You might see arguments.callee used in a situation similar to
this:
var items = [1,2,3,4,5,6,7];
// As we process the items, use setTimeout to give the UI thread time to update.
setTimeout(function () {
if (items.length === 0) {
finish();
}
else {
heavyProcessing(items.shift());
setTimeout(arguments.callee, 20); // Recur via arguments.callee
}
}, 20);
However, there is a more elegant solution: function expressions with a name that is only visible from within their own scope.
var factorialOf5 = (function factorial(n) {
return n === 0 ? 1 : n * factorial(n - 1);
}(5));
console.log(factorialOf5); // 120
console.log(factorial); // ReferenceError: factorial is not defined
To understand why this works, it is important to understand that Javascript has two different forms for creating functions which (perhaps frustratingly) look very similar.
Function declarations introduce a new, named function to the current scope. These are statements by themselves and cannot be combined with other expressions.
function name( [param*] ) {
[statement*]
}
Note that declarations really perform two operations: one, create a new function; two, bind that new function to name in the current scope.
Function expressions simply create a new function and return it. A function expression can be used as an argument to another function (think callbacks), assigned to variables, or invoked immediately.
function [name] ( [param*] ) {
[statement*]
}
Name is optional in function expressions, without it the function is anonymous, with it the only the function itself can refer to that name.
In the following example, foo, bar,
and arguments.callee all provide a medium to recursion inside the
function, however only foo is accessible from outside the
function.
var foo = function bar() {
return foo === bar
&& foo === arguments.callee
&& bar === arguments.callee;
}
foo() // true
bar // ReferenceError: bar is not defined
Not only does using a named function expression provide cleaner code than
accessing arguments.callee, it helps you out when it is time to
profile or debug your code. A stack trace consisting of ten "anonymous
function"s and line numbers is nowhere near as helpful as the named functions
will be.
On August 10th, 2010
On August 2nd, 2010
On July 23rd, 2010
On July 19th, 2010
On July 5th, 2010
On June 29th, 2010
On June 25th, 2010
On June 21st, 2010
On June 2nd, 2010
On May 20th, 2010
blog comments powered by Disqus