Why use named function expressions?
Asked Answered
C

5

103

We have two different way for doing function expression in JavaScript:

Named function expression (NFE):

var boo = function boo () {
  alert(1);
};

Anonymous function expression:

var boo = function () {
  alert(1);
};

And both of them can be called with boo();. I really can't see why/when I should use anonymous functions and when I should use Named Function Expressions. What difference is there between them?

Cockaleekie answered 11/3, 2013 at 10:31 Comment(2)
D
96

In the case of the anonymous function expression, the function is anonymous — literally, it has no name. The variable you're assigning it to has a name, but the function does not. (Update: That was true through ES5. As of ES2015 [aka ES6], often a function created with an anonymous expression gets a true name [but not an automatic identifier], read on...)

Names are useful. Names can be seen in stack traces, call stacks, lists of breakpoints, etc. Names are a Good Thing™.

(You used to have to beware of named function expressions in older versions of IE [IE8 and below], because they mistakenly created two completely separate function objects at two completely different times [more in my blog article Double take]. If you need to support IE8 [!!], it's probably best to stick with anonymous function expressions or function declarations, but avoid named function expressions.)

One key thing about a named function expression is that it creates an in-scope identifier with that name for the function within the functon body:

var x = function example() {
    console.log(typeof example); // "function"
};
x();
console.log(typeof example);     // "undefined"

As of ES2015, though, a lot of "anonymous" function expressions create functions with names, and this was predated by various modern JavaScript engines being quite smart about inferring names from context. In ES2015, your anonymous function expression results in a function with the name boo. However, even with ES2015+ semantics, the automatic identifier is not created:

var obj = {
    x: function() {
       console.log(typeof x);   // "undefined"
       console.log(obj.x.name); // "x"
    },
    y: function y() {
       console.log(typeof y);   // "function"
       console.log(obj.y.name); // "y"
    }
};
obj.x();
obj.y();

The assignment fo the function's name is done with the SetFunctionName abstract operation used in various operations in the spec.

The short version is basically any time an anonymous function expression appears on the right-hand side of something like an assignment or initialization, like:

var boo = function() { /*...*/ };

(or it could be let or const rather than var), or

var obj = {
    boo: function() { /*...*/ }
};

or

doSomething({
    boo: function() { /*...*/ }
});

(those last two are really the same thing), the resulting function will have a name (boo, in the examples).

There's an important, and intentional, exception: Assigning to a property on an existing object:

obj.boo = function() { /*...*/ }; // <== Does not get a name

This was because of information leak concerns raised when the new feature was going through the process of being added; details in my answer to another question here.

Diactinic answered 11/3, 2013 at 10:41 Comment(2)
It's worth noting there are at least two places in which using NFEs still gives concrete advantages: firstly, for functions intended to be used as constructors via the new operator (giving all such functions names makes the .constructor property more useful during debugging for figuring out what the heck some object is an instance of), and for function literals passed directly into a function without first being assigned to a property or variable (e.g. setTimeout(function () {/*do stuff*/});). Even Chrome shows these as (anonymous function) unless you help it along by naming them.Tortoiseshell
@MarkAmery: "is this still true? I...tried to CTRL-F for these rules and could not find them" Oh yes. :-) It's strewn throughout the spec rather than being in one place defining a set of rules, just search for "setFunctionName". I've added a small subset of links above, but it shows up in ~29 different places currently. I'd only be mildly surprised if your setTimeout example didn't grab the name from the formal argument declared for setTimeout, if it had one. :-) But yes, NFEs are definitely useful if you know you won't be dealing with old browsers that make a hash of them.Diactinic
T
26

Naming functions is useful if they need to reference themselves (e.g. for recursive calls). Indeed, if you are passing a literal function expression as an argument directly to another function, that function expression cannot directly reference itself in ES5 strict mode unless it is named.

For example, consider this code:

setTimeout(function sayMoo() {
    alert('MOO');
    setTimeout(sayMoo, 1000);
}, 1000);

It would be impossible to write this code quite this cleanly if the function expression passed to setTimeout were anonymous; we would need to assign it to a variable instead prior to the setTimeout call. This way, with a named function expression, is slightly shorter and neater.

It was historically possible to write code like this even using an anonymous function expression, by exploiting arguments.callee...

setTimeout(function () {
    alert('MOO');
    setTimeout(arguments.callee, 1000);
}, 1000);

... but arguments.callee is deprecated, and is outright forbidden in ES5 strict mode. Hence MDN advises:

Avoid using arguments.callee() by either giving function expressions a name or use a function declaration where a function must call itself.

(emphasis mine)

Tortoiseshell answered 19/2, 2015 at 0:49 Comment(0)
B
4

You should always use named function expressions, that's why:

  1. You can use the name of that function when you need recursion.

  2. Anonymous functions doesn't help when debugging as you can't see the name of the function that causes problems.

  3. When you do not name a function, later on its harder to understand what it's doing. Giving it a name makes it easier to understand.

var foo = function bar() {
    //some code...
};

foo();
bar(); // Error!

Here, for example, because the name bar is used within a function expression, it doesn't get declared in the outer scope. With named function expressions, the name of the function expression is enclosed within its own scope.

Bartolemo answered 12/4, 2018 at 1:19 Comment(0)
C
3

If a function is specified as a Function Expression, it can be given a name.

It will only be available inside the function (except IE8-).

var f = function sayHi(name) {
  alert( sayHi ); // Inside the function you can see the function code
};

alert( sayHi ); // (Error: undefined variable 'sayHi')

This name is intended for a reliable recursive function call, even if it is written to another variable.

In addition, the NFE (Named Function Expression) name CAN be overwritten with the Object.defineProperty(...) method as follows:

var test = function sayHi(name) {
  Object.defineProperty(test, 'name', { value: 'foo', configurable: true });
  alert( test.name ); // foo
};

test();

Note: that with the Function Declaration this can not be done. This "special" internal function name is specified only in the Function Expression syntax.

Capernaum answered 7/9, 2017 at 23:56 Comment(0)
D
1

Using named function expressions is better, when you want to be able to reference the function in question without having to rely on deprecated features such as arguments.callee.

Dominiquedominium answered 11/3, 2013 at 10:38 Comment(1)
That's more of a comment rather than an answer. Perhaps elaboration would be beneficialYance

© 2022 - 2024 — McMap. All rights reserved.