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

我们有两种不同的方式来在JavaScript中执行函数表达式:

命名函数表达式(NFE)

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

匿名函数表达式

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

并且可以用boo();调用它们boo(); 。 我真的不明白为什么/何时应该使用匿名函数,何时使用命名函数表达式。 他们之间有什么不同?


在匿名函数表达式的情况下,函数是匿名的 - 从字面上看,它没有名字。 你分配给它的变量有一个名字,但是这个函数没有。 (更新:通过ES5确实是如此,从ES2015 [又名ES6]开始,通常用匿名表达式创建的函数会得到一个真实姓名,请继续阅读...)

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

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

然而,从ES2015开始,很多“匿名”函数表达式都会使用名称创建函数,而此前由各种现代JavaScript引擎在从上下文推断名称方面非常聪明。 在ES2015中,匿名函数表达式产生一个名为boo的函数。 这遍布整个规范,而不是在一个地方定义一堆规则:搜索“SetFunctionName”的出现,目前可在以下位置找到:

  • §12.2.6.9(属性初始值语义)
  • §12.14.4(赋值运算符语义)
  • §12.14.5.2和§12.14.5.4(解构赋值语义)
  • §13.3.1.4( letconst声明的语义)
  • ......和一堆其他地方。
  • 短版本基本上是任何时候匿名函数表达式出现在类似赋值或初始化的东西的右侧,如:

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

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

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

    要么

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

    (后两者实际上是相同的东西),结果函数将会有一个名称(在示例中为boo )。

    有一个重要且有意的例外:在现有对象上分配属性:

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

    这是因为当新功能经历了被添加的过程时引发了信息泄露问题; 我在这里回答另一个问题的细节。


    命名函数在需要引用自身时非常有用(例如,用于递归调用)。 事实上,如果将直接函数表达式作为参数直接传递给另一个函数,则该函数表达式不能直接在ES5严格模式中引用自身,除非它被命名。

    例如,请考虑以下代码:

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

    如果传递给setTimeout的函数表达式是匿名的,那么编写这段代码就不可能这么干净。 我们需要在setTimeout调用之前将其分配给一个变量。 这样,使用一个命名的函数表达式,它会稍微短一点。

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

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

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

    避免使用arguments.callee() ,通过给函数表达式一个名字或者在函数必须调用它自己时使用函数声明。

    (强调我的)


    如果函数被指定为函数表达式,则可以给它一个名称。

    它只能在功能内部使用(IE8-除外)。

    该名称用于可靠的递归函数调用,即使它被写入另一个变量。

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

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

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

    var test = function sayHi(name) {
      sayHi = "тест"; // try to redefine
      alert( sayHi ); // function... (redefinition is unsuccessful )
    };
    
    test();
    
    链接地址: http://www.djcxy.com/p/17265.html

    上一篇: Why use named function expressions?

    下一篇: What is the difference between a function expression vs declaration in JavaScript?