为什么使用命名函数expression式

我们有两种不同的方式来在JavaScript中进行函数expression:

命名函数expression式(NFE)

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

匿名函数expression式

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

这两个都可以用boo();来调用boo(); 。 我真的不明白为什么/当我应该使用匿名函数,当我应该使用命名函数expression式。 他们之间有什么不同?

在匿名函数expression式的情况下,函数是匿名的 – 从字面上看,它没有名字。 你分配给它的variables有一个名字,但是这个函数没有。 (更新:通过ES5是真实的。从ES2015 [又名ES6],有时甚至一个匿名函数expression式导致一个真实名称的函数,阅读…)

名字是有用的。 名称可以在栈跟踪,调用堆栈,断点列表等中看到。名称是一个好东西™。

在IE(IE8及以下版本)的旧版本中,您必须小心命名的函数expression式,因为IE在两个完全不同的时间错误地创build了两个完全独立的函数对象(在我的博客文章Double take中更多 )。 如果您需要支持IE8,最好使用匿名函数expression式或函数声明 ,但避免使用命名函数expression式。

然而,从ES2015开始,许多“匿名”函数expression式用名称创build函数,而这种情况早已被各种现代JavaScript引擎所推崇,这些引擎在从上下文中推断名称方面非常聪明。 在ES2015中,匿名函数expression式产生一个名为boo的函数。 这是遍布整个规范,而不是在一个地方定义一堆规则:search“setFunctionName”,目前发现

  • §12.2.6.9(属性初始值语义)
  • §12.14.4(赋值运算符语义)
  • §12.14.5.2和§12.14.5.4 (解构赋值语义)
  • §13.3.1.4( letconst声明的语义)
  • …和其他一些地方。

短版本基本上是任何时候匿名函数expression式出现在类似于赋值或初始化的东西的右侧,如:

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

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

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

要么

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

要么

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

(最后两个是真的一样的东西) ,结果函数将有一个名字( boo ,在例子中)。

命名函数是有用的,如果他们需要引用自己(例如recursion调用)。 事实上,如果将直接函数expression式作为参数直接传递给另一个函数,则除非命名,否则该函数expression式不能直接在ES5严格模式中引用自身。

例如,考虑这个代码:

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

如果传递给setTimeout的函数expression式是匿名的,那么编写这个代码就不可能这么干净。 我们需要在setTimeout调用之前将其分配给一个variables。 这样,用一个命名的函数expression式,稍微短一些,整洁。

通过利用arguments.callee ,甚至可以使用匿名函数expression式来编写这样的代码,这在历史上是可能的。

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

…但是arguments.callee已经被弃用了,并且在ES5严格模式下是完全禁止的。 因此MDNbuild议:

避免使用arguments.callee() ,通过给函数expression式一个名字或者在函数必须调用自己的地方使用一个函数声明。

(重点是我的)

使用命名的函数expression式更好,当你想能够引用有问题的函数而不必依赖于诸如arguments.callee弃用特性。

如果函数被指定为函数expression式,则可以给它一个名字。

它只会在function内部使用(IE8-除外)。

这个名字是为了一个可靠的recursion函数调用,即使它被写入另一个variables。

请注意,对于函数声明,这不能完成。 这个“特殊的”内部函数名称仅在函数expression式语法中指定。

 var f = function sayHi(name) { alert( sayHi ); // Inside the function you can see the function code }; alert( sayHi ); // (Error: undefined variable 'sayHi') 

另外,NFE(命名函数expression式)名称不能被覆盖:

 var test = function sayHi(name) { sayHi = "тест"; // try to redefine alert( sayHi ); // function... (redefinition is unsuccessful ) }; test();