Perfection Kills

by kangax

Exploring Javascript by example

Named function expressions demystified

June 15th, 2009

After a couple of months, I have finally finished an article on named function expressions. It’s meant to demystify some of the common misconceptions I’ve seen on the web, take an in-depth look at cross-browser quirks and explain how to safely “work around” them. Quite obviously, it also explains what named function expressions are good for and how to “take advantage” of them in your applications.

If you have suggestions or find any mistakes, please let me know. Hope you like it.

http://kangax.github.com/nfe

Categories: Uncategorized

Comments (16)

  1. Gravatar

    Christof said on Jun 16, 2009 @ 11:39

    For a solution of name leaking and other stuff in IE would it not simply be possible to use: var f = function f() {} ? This way the variable name “f” will overwrite the leaked function name “f”? I guess the problem with leaking memory may be still there (and no way to null f either) but as you wrote not a big problem for not too many functions.

  2. Gravatar

    unscriptable said on Jun 17, 2009 @ 19:22

    Thanks for bringing this all together, kangax!

    I can remember hitting your JScript bug #4 back in 2005 while trying to write a cross-browser XHR wrapper and spending days being bewildered why IE wasn’t working. I’ve definitely hit the Safari 2 bugs as well. I swear the following forces Safari 2.0 to bail, too, but I haven’t bothered to test it recently:

    var obj = {
      f: function f () {}
    };
    
  3. Gravatar

    Bertrand Le Roy said on Jun 18, 2009 @ 15:25

    Thanks for the greatly documented article.
    There is one particular common construct that doesn’t work in Safari 2 that we found we had to work around: if you want to set-up an object with named function fields (typically a prototype) like this: var a = {foo: function foo() {} }. You need to take the function out for it to work: function foo() {}; var a = {foo: foo}; Of course, var a = {foo: function() {} }; works everywhere (and that’s what we do in release mode) but you lose the benefits of named functions in debug mode.

  4. Gravatar

    kangax (article author) said on Jun 18, 2009 @ 20:32

    @Christof

    I remember I had similar idea and tests showed that memory leak was indeed less severe. I wasn’t very fond of such solution, as it seemed like it would make code more verbose.

    Consider:

      if (smth) {
        addEvent = function addEvent(){ ... };
      }
      else if (smthElse) {
        addEvent = function addEvent(){ ... };
      }
      else {
        addEvent = function addEvent(){ ... };
      }
    

    I think it might be a good idea to mention this in the article. Thanks for your feedback!

    @unscriptable

    I remember hitting these bugs back in the days as well : ) Hopefully, this reference will make such experience less painful for future developers.

    @unscriptable, @Bertrand

    An example you mention seems to confirms my theory: that only function expressions that are part of AssignmentExpression‘s are parsed correctly.

    I bet if you change it to something like this, it will actually work as expected:

      var temp;
      ...
      var obj = {
        x: (temp = function x(){ ... })
        ...
      }
      ...
      temp = null;
    

    (Essentially turning expression into assignment one)

  5. Gravatar

    nimmr said on Jun 19, 2009 @ 1:01

    Well written article and an interesting subject.

  6. Gravatar

    Wilq32 said on Jun 19, 2009 @ 4:32

    I really enjoy reading this article. Usually i stops in the middle but this time i read all :) Cheers !:)

  7. Gravatar

    Gianni Chiappetta (gf3) said on Jun 30, 2009 @ 21:15

    That really cleared up some grey areas for me, thanks kangax. I’ll undoubtedly be referring to this article while writing future scripts, thanks for the great reference.

  8. Gravatar

    Dmitry A. Soshnikov said on Oct 21, 2009 @ 7:03

    Hi, kangax! As I’ve already mentioned – thanks for a good article and useful comments for articles in my blog.

    I also have some additions to this article – about NFE bugs in JScript.

    You might be wondering how all this mess with different function objects compares to arguments.callee. Does callee reference f or g? Let’s take a look:
    [...]
    As you can see, arguments.callee references same object as f identifier.

    But indeed arguments.callee references to that object which calls the function (or better to say functions – as there’re two function objects):

    var f = function g(){
    return [
    arguments.callee == f,
    arguments.callee == g
    ];
    };
    f(); // [true, false]

    // but:
    g(); // [false, true]

    Moreover, if to call function right after creation, arguments.callee won’t be equal neither to [f] nor to [g]:

    var f = function g(){

    alert([
    arguments.callee == f,
    arguments.callee == g
    ]);

    }(); // [false, false]

    First [false] sure correct (as [f] is not assigned value yet which should be result of [g] – undefined), but the second one [false] – is again JScript’s bug and I guess [arguments.callee] in this moment references to that second function object.

    I mentioned that in new section of my article – http://javascript.ru/blog/Dmitry-A.-Soshnikov/Tonkosti-ECMA-262-3.-CHast-5.-Funkcii.#nfe-i-jscript

  9. Gravatar

    Dmitry A. Soshnikov said on Oct 21, 2009 @ 7:17

    Forgot this one (if you have premoderation of the comments you can join this comment and the previous one):

    Example #3: Named function expression creates TWO DISTINCT function objects!

    var f = function g(){};
    f === g; // false

    f.expando = ‘foo’;
    g.expando; // undefined

    It’s actually related with assignment statement together with description function object. In this case really two different objects will be created. But this bug is not taking place if to create “NFE” (which better to say – FD in JScript) with e.g. grouping operator:

    (function g(){}); // should be NFE, but in IE it looks like FD

    var f = g;
    f === g; // true

    f.expando = ‘foo’;
    g.expando; // ‘foo’

  10. Gravatar

    kangax (article author) said on Oct 30, 2009 @ 12:24

    Dmitry, thanks for these additions.

    I corrected [true, false]/[false, true] example (although only in my local copy at the moment). An example with [false, false] return value (when function is being evaluated immediately) kind of makes sense. As you rightfully noticed, during evaluation f is not yet being assigned a value, and g actually references another function object — the one created during variable declaration phase : )

    As far as your (function g(){}) example, I think it can all be explained pretty simple as well. In a conforming environment, (function g(){}) is a function expression that’s not being assigned to anything. It’s simply evaluated and can be discarded immediately (since no references to it exist).

    However, as we know, in JScript, that expression is parsed as plain function declaration and g becomes available to the entire scope. Later, at run time, this expression is being evaluated in JScript, and another function object is being created. This another function object is then immediately discarded just like it should.

    So, when you later assign that g to another variable — f, they obviously end up referencing the very same function object — the one created during variable declaration, not the one created at run time (since that one was discarded immediately).

  11. Gravatar

    Pierre Spring said on Jun 5, 2010 @ 15:58

    Hi.

    Thank you for this fantastic article. I learned a lot!

    A tiny error happened in the title of the Example #4 of the JScript section, where you write “Function declaration” instead of “Named function expression”… But that is just a detail…

    Yours … Pierre

  12. Gravatar

    esquifit said on Jan 1, 2012 @ 2:44

    Thank you for the detailed explanation. There is statement though that seem not be quite right:
    Function statements are NOT declared during variable instantiation. They are declared at run time, just like function expressions. However, once declared, function statement’s identifier becomes available to the entire scope of the function. I tested it with IE 8 and Firefox 8 and I got this in both cases:

    typeof foo; // "function", not 'undefined' as stated.
    if (true) {
    // once block is entered, `foo` becomes declared and available to the entire scope
    function foo(){ return 1; }
    }
    else {
    // this block is never entered, and `foo` is never redeclared
    function foo(){ return 2; }
    }

    Maybe I’m misinterpreting something?

  13. Gravatar

    witek said on Jan 1, 2012 @ 9:21

    I think named function expression is not only usefull for debuging, but also for “anonymous” recursion. Normally in functional languages, it is done using Y-combinator, but is quite hard contecpt, by giving a function name which is only available inside a function it is simple to create almost-anonymous recursvie function.

    var fact = (function f(n) {
    if (n == 0) return 1;
    return n*f(n-1);
    });

    You can safely change “var fact”, to something different (or use in different expression context), and it will still work!

  14. Gravatar

    Devin Rhode said on Dec 30, 2012 @ 17:20

    Are named closures ok? Like this:

    $el.click(function elOnClick() {

    });

    (function aFile() {

    })();

  15. Gravatar

    Devin Rhode said on Dec 31, 2012 @ 11:09

    So, generally, the more often you can use function declarations, the better, because you get function names without errors or memory leaks. (jQuery has about 55 function declarations!)

    But – what’s an easy and clean way to expose a function for external use, but allow it to access some private variables in a library?

    Here’s a pattern I _used_ to do:

    var publicFn;
    (function myLibrary() {
    publicFn = function publicFn() {

    };
    })();

    Seems like a better pattern would be:

    var publicFn;
    (function myLibrary() {
    publicFn = (function(){
    function publicFn() {

    }
    return publicFn;
    })();
    })();

    For a library building up one object, like $ or _, the corresponding style would be:

    var _;
    (function underscoreJS(){
    function _each(…) {
    //…
    }
    _.each = _each;
    })();

    Correct?

  16. Gravatar

    Evgeni Petrov said on Mar 11, 2013 @ 3:13

    Thank you.

Trackbacks

Leave a Comment

Please, don't forget to escape your input (<, > and &). Wrap code sections with <pre>

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>