5

I was told that you must always declare functions in JavaScript. Is that true? What is the advantage of it?

I usually assign functions to a variable as such:

var foo = function() {};

But supposedly this is wrong, something to do stack tracing. Can someone please explain? I was told to do:

var foo = function fooBar() {};

Would it make sense if it's assigned to an object?

var Foo = {};
Foo.Bar = function Bar() {};

Mind you these functions are not inside of the global scope nor self-executed nor used multiple times.

DevNoob
  • 61
  • 3
  • 4
    possible duplicate of [var functionName = function() {} vs function functionName() {}](http://stackoverflow.com/questions/336859/var-functionname-function-vs-function-functionname) – Mike Robinson Apr 01 '15 at 21:20
  • 1
    Seems like your question is about assigning functions a name. Yes, that helps with stack tracing so you don't see merely a bunch of 'anonymous function' entries. – JAL Apr 01 '15 at 21:21
  • @MikeRobinson that questions is more about hoisting. I know the difference between those two functions. Please re-read the question. – DevNoob Apr 01 '15 at 21:23
  • @JAL can you please elaborate? – DevNoob Apr 01 '15 at 21:23
  • @MikeRobinson — No. That question is about function expressions and function declarations, not named function expressions and anonymous function expressions. – Quentin Apr 01 '15 at 21:24
  • @DevNoob: If you place a breakpoint in one of those anonymous functions that's been assigned to a variable, the callstack will not display the variable name (which is completely independent of the function itself; it merely holds a reference to it) but rather some generic auto-generated anonymous function name. The advantage is mainly an improved debugging experience. – Cameron Apr 01 '15 at 21:26
  • 1
    Be wary: if you need to support <= IE8, named function expressions can cause a whole lot of headache. It's been well documented, but this is a good summary: http://kangax.github.io/nfe/#jscript-bugs – Jesse Kernaghan Apr 01 '15 at 21:48

1 Answers1

3

First of all, a small note on terminology: what you have isn’t a function declaration. This is a function declaration:

function fooBar() {
}

It creates a function named fooBar accessible through the variable fooBar. This is an assignment involving a named function expression:

var foo = function fooBar() {
};

The function’s name is still fooBar, but the function is only bound to a fooBar variable inside the function itself and not outside. The fact that it does make the function accessible inside its scope without needing to refer to a variable in an outer scope, though, means that there are two reasons to name it:

  • For the ability to refer to the function inside itself regardless of code in the outer function!

    This can return whatever the outer function wants:

    function fooBar() {
        return fooBar.toString();
    }
    
    var baz = fooBar;
    fooBar = 5;
    baz(); // "5"
    

    This is always consistent:

    var fooBar = function fooBar() {
        return fooBar.toString();
    };
    
    var baz = fooBar;
    fooBar = 5;
    baz(); // "function fooBar() { …"
    
  • And yes, for a more detailed stack trace:

    function trace(func) {
        try {
            func();
        } catch (error) {
            console.log(error.stack);
        }
    }
    
    trace(function () {
        throw new Error("Bad thing");
    });
    /*
    Error: Bad thing
        at /home/ryan/test.js:10:18
        at trace (/home/ryan/test.js:3:16)
        at Object.<anonymous> (/home/ryan/test.js:9:8)
        at Module._compile (module.js:410:26)
        at Object.Module._extensions..js (module.js:428:10)
        at Module.load (module.js:335:32)
        at Function.Module._load (module.js:290:12)
        at Function.Module.runMain (module.js:451:10)
        at startup (node.js:123:18)
        at node.js:866:3
    */
    
    trace(function descriptiveName() {
        throw new Error("Bad thing");
    });
    /*
    Error: Bad thing
        at descriptiveName (/home/ryan/test.js:14:18)
        at trace (/home/ryan/test.js:3:16)
        at Object.<anonymous> (/home/ryan/test.js:13:8)
        at Module._compile (module.js:410:26)
        at Object.Module._extensions..js (module.js:428:10)
        at Module.load (module.js:335:32)
        at Function.Module._load (module.js:290:12)
        at Function.Module.runMain (module.js:451:10)
        at startup (node.js:123:18)
        at node.js:866:3
    */
    

    (Node.js pictured here.) Note the descriptiveName at the top of the second stack trace. This is especially convenient when you have slightly complicated systems of asynchronous callbacks, events, methods on objects that are passed around, and so on.

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • You could perhaps also name IIFE to describe what a code block does. E.g. `(function applyFixIfNeeded() { //fix in here }());` rather than using comments likes `//This applies a fix` with code below. I actually prefer declaring functions at the bottom and invoke them at the top for this, but I've used that form in the past. – plalx Apr 01 '15 at 21:36