一尘不染

JavaScript为什么要使用命名函数表达式?

javascript

我们可以通过两种不同的方式在JavaScript中执行函数表达式:

命名函数表达式(NFE)

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

匿名函数表达式

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

而且两个都可以用调用boo();。我真的看不到为什么/何时应该使用匿名函数以及何时应该使用命名函数表达式。他们之间有什么区别?


阅读 540

收藏
2020-04-25

共1个答案

一尘不染

对于匿名函数表达式,该函数是匿名的从字面上看,它没有名称。您要为其分配变量的变量具有名称,但是该函数没有。
_(更新:这在ES5中是正确的。从ES2015[akaES6]开始,通常使用匿名表达式创建的函数会获得真实名称[但不是自动标识符],请继续阅读…)

名称很有用。可以在堆栈跟踪,调用堆栈,断点列表等中看到名称。名称是Good Thing™。

(您以前必须提防IE[IE8及以下版本的IE较旧版本中的命名函数表达式,因为它们在两个完全不同的时间错误地创建了两个完全独立的函数对象中的更多内容。)支持IE8[!!],最好使用匿名函数表达式或函数声明,但要避免使用命名函数表达式。)

关于命名函数表达式的关键一件事是,它在函数体中为函数创建了一个范围内的标识符:

var x = function example() {

    console.log(typeof example); // "function"

};

x();

console.log(typeof example);     // "undefined"

不过,从ES2015开始,许多“匿名”函数表达式会创建带有名称的函数,而这要早于各种现代JavaScript引擎,它们非常聪明地从上下文推断名称。在ES2015中,您的匿名函数表达式将产生名称为的函数boo。但是,即使使用ES2015
+语义,也不会创建自动标识符:

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();

函数名称的分配是通过规范中各种操作中使用的SetFunctionName抽象操作完成的。

简短版本基本上是任何时候匿名函数表达式出现在诸如赋值或初始化之类的右侧时,例如:

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

(或者可以是letconst而不是var,或者

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

要么

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

(最后两个实际上是同一件事) ,结果函数将具有名称(boo在示例中为)。

有一个重要的,有意的例外:分配给现有对象的属性:

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

这是由于在添加新功能时引发了对信息泄漏的担忧。我在这里回答另一个问题的细节。

2020-04-25