在Javascript中,何时需要将命名函数分配给变量?

在Javascript中,何时需要将命名函数分配给变量?,javascript,ecmascript-6,Javascript,Ecmascript 6,在Babel JS()的在线回复中,当我键入时: let a = (x) => x+1 它将被传送到: "use strict"; var a = function a(x) { return x + 1; }; 这里的var a=function a(x)看起来有点让我困惑,因为var a=function(x)或function a(x)就足够了 是否有人知道何时以及为什么有必要为变量指定一个名为的函数 function a(x) { } var a = function

在Babel JS()的在线回复中,当我键入时:

let a = (x) => x+1
它将被传送到:

"use strict";

var a = function a(x) {
  return x + 1;
};
这里的
var a=function a(x)
看起来有点让我困惑,因为
var a=function(x)
function a(x)
就足够了

是否有人知道何时以及为什么有必要为变量指定一个名为的函数

function a(x) { }
var a = function a(x) { }
然后,函数被提升到封闭范围的顶部,
a
在整个范围内的解析时间立即可用

然而,当你写作时:

function a(x) { }
var a = function a(x) { }
然后
var a
将不会在封闭范围内定义值,直到实际执行这一行

但是,在该函数中,不同的
a
将作为函数本身的局部范围引用存在


通过使用
let a=function…
construct Babel更符合后一种形式,确保
a
在运行时分配给(命名)函数表达式,而不是使用解析时函数声明。

这里有两个不同的问题:

  • 定义或表达函数的不同方式之间有什么区别
  • 为什么
    让a=(x)=>x+1
    以这种方式传输
  • 为了回答(2),我们需要理解(1)——这已经在某某和其他地方进行了广泛的讨论


    问题1 让我们看一下您提到的三个备选方案:

    函数声明

    function a(x) { ... }
    
    var a = function (x) { ... }
    
    var a = function a(x) { ... }
    
    从语法上讲,它们必须始终以
    函数
    ()开头。它们在解析时被提升,并在本地范围内创建一个命名函数

    (匿名)函数表达式

    function a(x) { ... }
    
    var a = function (x) { ... }
    
    var a = function a(x) { ... }
    
    var a
    本身将在解析时被提升,但它将
    未定义
    ,直到该行在运行时执行为止

    命名函数表达式

    function a(x) { ... }
    
    var a = function (x) { ... }
    
    var a = function a(x) { ... }
    
    虽然语法使它看起来像是对函数声明的赋值,但实际上它只是一个带名称的函数表达式。我觉得这很混乱,但这就是语法

    最大的区别在于函数声明和函数表达式之间。通过声明,您可以执行以下操作:

    a(1);
    function a(x) { return x + 1; }
    
    尽管尝试使用函数表达式(命名或匿名)执行此操作将导致错误


    问题2
  • 为什么让a=(x)=>x+1以这种方式传输
  • 我们将箭头函数
    (x)=>x+1
    分配给具有
    let
    的块作用域变量,因此我们应该期望
    a
    在运行时执行这一行之后才会定义。这应该是函数表达式,而不是函数声明

    最后,为什么
    让a=(x)=>x+1
    传输到命名函数表达式而不是匿名函数表达式?有什么区别?正如Alnitak和其他人指出的那样:

    • 函数名出现在调试器中,这可能会有所帮助
    • 命名函数定义内的作用域具有对函数本身的引用。这允许递归和访问包含函数的属性
    因此,命名函数表达式有一些匿名函数表达式没有的好特性。但实际上似乎在这里应该发生什么问题上存在分歧。根据:

    箭头函数总是匿名的

    鉴于to表示:

    [从ES6开始]许多“匿名”函数表达式创建具有名称的函数,而在这之前,各种现代JavaScript引擎非常擅长从上下文推断名称……这在整个规范中随处可见

    其他参考资料:


    我发现处理这个问题的最佳方法是使用。

    这似乎是根据标准()进行的:

    AssignmentExpression[In,Yield]:LeftHandSideExpression[?Yield]=AssignmentExpression[?In,Yield]

    1.如果LeftHandSideExpression既不是ObjectLiteral也不是ArrayLiteral,则
    a。让lref作为计算LeftHandSideExpression的结果。
    b。返回初始值(lref)。
    c。让rref作为赋值表达式求值的结果。
    d。设rval为GetValue(rref)。
    e。如果LeftHandSideExpression的IsAnonymousFunctionDefinition(AssignmentExpression)和IsIdentifierRef均为true,则
    I.将hasNameProperty设为HasOwnProperty(rval,“名称”)。
    二,。ReturnIfAbrupt(hasNameProperty)。
    III.如果hasNameProperty为false,执行SetFunctionName(rval,GetReferencedName(lref))

    因此,每当计算未命名函数表达式对命名标识符的赋值时,函数名应设置为标识符名

    Babel遵循此过程,并生成兼容的ES5实现。
    Chrome(v46.0.2490.71,V8引擎…)不遵循此过程,在这种情况下,
    name
    等于
    '


    至于问题本身

    在Javascript中,何时需要将命名函数分配给变量


    答案是永远不要。由开发人员决定是否/何时使用命名函数。这一决定可以归结为对名称的特定需求(如“字符串化”函数时)或调试需求(更好的堆栈跟踪…。

    这不是必需的,但如果函数没有名称,在某些浏览器中,它不会在堆栈跟踪中显示为“函数a”。因此,命名函数有助于简化调试。否则它们将显示为“匿名函数”。@Shilly还有另一个区别-命名函数将其名称暴露到自己的作用域中。@Alnitak:错误。它仅向作用域公开其名称(并使用提升)