命名功能

函数可以是命名的或未命名的( 匿名函数 ):

var namedSum = function sum (a, b) { // named
    return a + b;
}

var anonSum = function (a, b) { // anonymous
    return a + b;
}

namedSum(1, 3);
anonSum(1, 3);

4
4

但是他们的名字属于他们自己的范围:

var sumTwoNumbers = function sum (a, b) {
    return a + b;
}

sum(1, 3);

未捕获的 ReferenceError:未定义 sum

命名函数与多个场景中的匿名函数不同:

  • 在调试时,函数的名称将出现在错误/堆栈跟踪中
  • 命名函数被挂起而匿名函数则不被挂起
  • 处理递归时,命名函数和匿名函数的行为会有所不同
  • 根据 ECMAScript 版本,命名和匿名函数可能会以不同方式处理函数 name 属性

命名函数被悬挂

使用匿名函数时,只能在声明行之后调用该函数,而在声明之前可以调用命名函数。考虑

foo();
var foo = function () { // using an anonymous function
    console.log('bar');
}

未捕获的 TypeError:foo 不是函数

foo();
function foo () { // using a named function
    console.log('bar');
}

bar

递归方案中的命名函数

递归函数可以定义为:

var say = function (times) {
    if (times > 0) {
        console.log('Hello!');

        say(times - 1);
    }
}

//you could call 'say' directly, 
//but this way just illustrates the example
var sayHelloTimes = say;

sayHelloTimes(2);

你好!
你好!

如果你的代码中某处原始函数绑定被重新定义怎么办?

var say = function (times) {
    if (times > 0) {
        console.log('Hello!');

        say(times - 1);
    }
}

var sayHelloTimes = say;
say = "oops";

sayHelloTimes(2);

你好!
未捕获的 TypeError:说不是函数

这可以使用命名函数来解决

// The outer variable can even have the same name as the function
// as they are contained in different scopes
var say = function say (times) {
    if (times > 0) {
        console.log('Hello!');

        // this time, 'say' doesn't use the outer variable
        // it uses the named function
        say(times - 1);
    }
}

var sayHelloTimes = say;
say = "oops";

sayHelloTimes(2);

你好!
你好!

作为奖励,命名函数不能设置为 undefined,即使是从内部:

var say = function say (times) {
    // this does nothing
    say = undefined;
    
    if (times > 0) {
        console.log('Hello!');

        // this time, 'say' doesn't use the outer variable
        // it's using the named function
        say(times - 1);
    }
}

var sayHelloTimes = say;
say = "oops";

sayHelloTimes(2);

你好!
你好!

函数的 name 属性

在 ES6 之前,命名函数将 name 属性设置为其函数名称,匿名函数将其 name 属性设置为空字符串。

Version <= 五

var foo = function () {}
console.log(foo.name); // outputs ''

function foo () {}
console.log(foo.name); // outputs 'foo'

在 ES6 之后,命名和未命名的函数都设置了他们的 name 属性:

Version >= 6

var foo = function () {}
console.log(foo.name); // outputs 'foo'

function foo () {}
console.log(foo.name); // outputs 'foo'

var foo = function bar () {}
console.log(foo.name); // outputs 'bar'