为什么使用命名函数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(
let
和const
声明的语义) - …和其他一些地方。
短版本基本上是任何时候匿名函数expression式出现在类似于赋值或初始化的东西的右侧,如:
var boo = function() { /*...*/ };
(或者它可以是let
或const
而不是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();