Thursday, June 18th, 2009

Named function expressions in incredible detail

Category: Articles, JavaScript

The intrepid JS hacker Juriy “kangax” Zaytsev has an incredibly detailed post on demystifying named function expressions:

Surprisingly, a topic of named function expressions doesn’t seem to be covered well enough on the web. This is probably why there are so many misconceptions floating around. In this article, I’ll try to summarize both – theoretical and practical aspects of these wonderful Javascript constructs; the good, bad and ugly parts of them.

In a nutshell, named function expressions are useful for one thing only – descriptive function names in debuggers and profilers. Well, there is also a possibility of using function names for recursion, but you will soon see that this is often impractical nowadays. If you don’t care about debugging experience, you have nothing to worry about. Otherwise, read on to see some of the cross-browser glitches you would have to deal with and tips on how work around them.

He then goes into a ton of examples of weirdness in different browsers, and fun code like this:


  1. var f = function g() {
  2.         return 1;
  3.     };
  4.     if (false) {
  5.         f = function g(){
  6.             return 2;
  7.         }
  8.     };
  9.     g(); // 2



  1. var f = function g(){
  2.     return [
  3.       arguments.callee == f,
  4.       arguments.callee == g
  5.     ];
  6.   };
  7.   f(); // [true, false]

Finally, he shows a couple of techniques for using these correctly in the real world need of shimming:


  1. // 1) enclose declaration with a separate scope
  2.   var addEvent = (function(){
  4.     var docEl = document.documentElement;
  6.     // 2) declare a variable to assign function to
  7.     var fn;
  9.     if (docEl.addEventListener) {
  11.       // 3) make sure to give function a descriptive identifier
  12.       fn = function addEvent(element, eventName, callback) {
  13.         element.addEventListener(eventName, callback, false);
  14.       }
  15.     }
  16.     else if (docEl.attachEvent) {
  17.       fn = function addEvent(element, eventName, callback) {
  18.         element.attachEvent('on' + eventName, callback);
  19.       }
  20.     }
  21.     else {
  22.       fn = function addEvent(element, eventName, callback) {
  23.         element['on' + eventName] = callback;
  24.       }
  25.     }
  27.     // 4) clean up `addEvent` function created by JScript
  28.     //    make sure to either prepend assignment with `var`,
  29.     //    or declare `addEvent` at the top of the function
  30.     var addEvent = null;
  32.     // 5) finally return function referenced by `fn`
  33.     return fn;
  34.   })();

Posted by Dion Almaer at 6:22 am

4.1 rating from 40 votes


Comments feed TrackBack URI

Most interesting ressource I’ve read this year.
Thanks kangax !

Comment by ywg — June 18, 2009

It’s too bad the nulling shown in step 4 actually frees up memory, looks like some serious overkill, garbage collectors that don’t free up the memory shown in step 4 have room for improvement.

Comment by Jadet — June 18, 2009

Perhaps I’m misunderstanding, but why is example #1 unintuitive?

It seems to obey function level scoping. If I have:

function g() { return 1; }
if(false) {
function g() { return 2; }

Of course, you’d expect g() to return 2, JS doesn’t have a different scope for if statements. It’s identical to:

var g;
g = function() { return 1; }
g = function() { return 2; }

What am I missing?

Comment by zachleat — June 18, 2009

@zachleat I think you missed a lot. Try reading the post again.
function g() { … } is a function declaration. While var g = function() { … } is an unnamed function expression.
Quote from kangax’s post:
“Another important trait of function declarations is that declaring them conditionally is non-standardized and varies across different environments. You should never rely on functions being declared conditionally and use function expressions instead.”
“Never do this! Some browsers will declare `foo` as the one returning ‘first’, while others – returning ‘second’ “

Comment by jdalton — June 18, 2009

What zachleat says is true, if you’re familiar with the ECMA standard. The example,

function g() { return 1; }
if(false) {
function g() { return 2; }

is technically a syntax error. Function declarations are evaluated prior to script execution, and multiple declarations of the same function in the same scope is invalid. Some engines favor the second declaration simply because handling of the error is not defined.

Comment by eyelidlessness — June 18, 2009

@eyelidlessness – I could be wrong, I have been known to mis-read spec on more than on occasion. But in ECMA 5 draft,
13 Function Declaration (see 10.6)
10.6 Declaration Binding Instantiation
funcAlreadyDeclared is the result of calling env’s HasBinding concrete method passing fn as the argument. If its not already declared it calls CreateMutableBinding(..). Then it calls SetMutableBinding(…)
It doesn’t seem to call CreateImmutableBinding().
Which part of the spec are you referencing?

Comment by jdalton — June 18, 2009

Why do JS language designers are so ignorant of the prior art?

JavaScript is ought to have a variable binding construct, “let” or something. Then you wouldn’t need so much monkeying.

Actually, “var I = function(x){return x}” and “function I(x){return x}” have a subtle difference. The latter permits mutually recursive definitions, while the former is pretty limited in this respect.

Now, if we give people that “let” form (and also a “let*” in Scheme parlance), we don’t need to “mistify” ourselves with nonsense like the “named function expressions”.

Comment by chiaroscuro — June 18, 2009

Thank you!

I think you’re missing the difference between declaration and expression. What @jdalton said should pretty much answer your question.

I don’t see how two function declarations with same-named identifier is a syntax error in ES3. Could you point me to a particular section in the specs describing this?

Comment by kangax — June 18, 2009

Thanks guys, glad I asked!

Comment by zachleat — June 19, 2009


Also, named function expressions are necessary for recursion since arguments.callee is being removed.

Comment by TNO — June 19, 2009

Leave a comment

You must be logged in to post a comment.