Please Name Your Functions Thursday, 5 July 2007
I have updated this entry to address the JScript FunctionExpression Identifier bug (see below).
Giving a name to a function allows anyone to inspect the stack trace in any debugger and see the function's name, not "anonymous" or "no name".
A named function has an identifier following the function keyword.
The ECMAScript production for a FunctionExpression is as follows:
function Identifieropt ( FormalParameterListopt ){ FunctionBody }
Example
var foo = function foo() {
};
It is just as important to name constructor functions, too.
Don't do this:
/**
* @class Board. Used for creating board games (like checkers).
* @constructor
* @param x {Number} - number of horizontal squares
* @param y {Number} - number of vertical squares
*/
com.example.game.Board = function ( x, y ) {
};
Do this instead:
/** @constructor
* @param x {Number} - number of horizontal squares
* @param y {Number} - number of vertical squares
*/
com.example.game.Board = function Board( x, y ) {
};
It is just as important to name methods, too.
Object Literals
com.example.game.Board.prototype = {
/**
* @return squares {Array} a copy of the game's squares Array.
* Modifying the returned array will have no effect on the game itself.
*/
getSquares : function getSquares() {
return this.squares.concat();
}
// DO NOT DO THIS. getScore should point to a named function.
,getScore : function /*name goes here*/() {
}
,toString : function boardToString() {
return this.name + ", " + this.getScore();
}
};
Browser Compatibility
Safari <= 2 cannot handle named functions in object literals and will fail on interpreting the perfectly valid JavaScript file (bug 4698). The Safari bug has been fixed.
Internet Explorer has the unwanted side effect also interpreting a FunctionExpression as a FunctionDeclaration to the containing scope.
Microsoft is violating the ECMA-262 spec (pdf) (Citation of ECMA Spec: 1).
JScript FunctionExpression Identifier bug
The problem can be explained with an example:
var meth = function ident() {
// The identifier 'ident' may be legally referenced from within the function.
alert( ident == meth ); // true, (actually false in IE);
};
// The variable 'ident' must not be affected by the function identifier.
alert( ident ); // must be undefined, but not in IE.
The above examples illustrate that IE will leak a function declaration in the containing scope.
This seems to be due to faulty lexical parsing on the first pass. This is further evidenced by the following example that illustrates JScript overriding the first function declaration with the second.
if (true) {
function f() { return true; }
} else {
function f() { return false; }
}
// IE will choose "false" returning function.
alert('Conditionally Delcared Function: ' + f());
However, a FunctionExpression is not parsed on the first pass, and is correctly parsed in JScript (and JavaScript, of course).
var f;
if (true) {
f = function () { return true; };
} else {
f = function () { return false; };
}
// IE chooses the 'true' returning function this time.
msg('Conditional FunctionExpression: ' + f());
How to handle the JScript FunctionExpression Identifier bug?
To avoid unwanted side effects, either:
- Do not use an identifier, or
- wrap the code that uses identifiers in anonymous function
Example
(function(){ // Enclosing scope.
com.example.game.Board = function Board( x, y ) {
...
};
com.example.game.Board.prototype = {
getSquares : function getSquares() {
return this.squares.concat(); // defensive copy.
}
};
})();
The above example will cause a scope to be created to "catch" a FunctionDeclaration that can be created in Microsoft JScript.
Consider Other Developers
You might be thinking: "It's not that big a deal, I can figure my code out." But will someone else be able to figure out a stack trace of "no name" functions in Firebug?
If You're Writing Library Code
You should name your functions.
It can be very difficult to pinpoint the actual function in the source code from a stack trace that contains anonymous functions referring to external library code that you did not write. When the code uses subclassing, it is even harder to find the actual method that caused the problem.
I sometimes have to resort to calling toString() on
the function object in the debugger, copying that text, then searching for that text in my IDE. It works,
but nobody should have to resort to those types of tactics.
Wouldn't it make more sense to just name the function in the first place? Something about an ounce of prevention...
If You're Writing Implementation Code
You should name your functions.
Most errors will start out in implementation code. If the first error in the stack trace is anonymous, it will be harder to debug and take more time.
Summary
Naming your functions is an easy way to make your code more explicit and easier to debug. Due to problems in Microsoft's JScript engine, FunctionDeclarations and FunctionExpressions with an Identifier must be used with care.
References
- From the EMCA-262 specification.
NOTE
The Identifier in a
FunctionExpressioncan be referenced from inside theFunctionExpression'sFunctionBodyto allow the function to call itself recursively. However, unlike in aFunctionDeclaration, the Identifier in aFunctionExpressioncannot be referenced from and does not affect the scope enclosing theFunctionExpression. - ECMAScript's FunctionDeclaration versus FunctionExpression, by Hallvord R. M. Steen.
- Core JavaScript 1.5 Reference:Functions
Technorati Tags: JavaScript
PS: Something's funky with the formatting... I think it happens right after the first code example at the start of the article.
If I am stepping through code and I see a function that has a problem, I might want to see the caller.
I can insert a watch.
caller
If the function is anonymous, then I can use
caller.toString()
and then search in the IDE.
About the formatting: I had to disable smilies. that is too bad, but it appears that smilies plugin was causing a problem :(


AnimTree
Garrett,
Awesome article. I can't tell you how many times I've scratched my head trying to figure out where a problem was coming from. I'll keep this in mind and be sure to follow your suggestions.
What question I had was when naming your functions, which function do you use when calling that function? In the case of the "toString" function in the Board class:
Do you call toString() or boardToString() ?