在Babel JS的在线REPL(http://babeljs.io/repl/)中,当我输入时:
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)
就足够了。
有没有人知道何时以及为什么有必要将命名函数分配给变量?
答案 0 :(得分:6)
这里有两个不同的问题:
let a = (x) => x + 1
会以这种方式进行转换?为了回答(2)我们需要理解(1) - 已在SO和其他地方广泛讨论过。让我们来看看你提到的三个选择:
功能声明:
function a(x) { ... }
从语法上讲,这些必须始终以function
(reference)开头。它们在分析时提升并在本地范围内创建一个命名函数。
(匿名)函数表达式:
var a = function (x) { ... }
var a
本身将在解析时提升,但在运行时执行此行之前它将为undefined
。
命名函数表达式:
var a = function a(x) { ... }
虽然语法使它看起来像是对函数声明的赋值,但这实际上只是一个带有名称的函数表达式。我发现这令人困惑,但这就是语法。
函数声明和函数表达式之间存在很大差异。通过声明,您可以:
a(1);
function a(x) { return x + 1; }
虽然尝试使用函数表达式(名为或匿名)会导致错误。
应该直观地清楚为什么let a = (x) => x + 1
应该不被转换为函数声明。我们将箭头函数(x) => x + 1
分配给带有let
的块作用域变量,因此我们应该期望在运行时执行此行之后才定义a
。
所以,我们还有一个问题:为什么let a = (x) => x + 1
被转换为命名函数表达式而不是匿名函数表达式?有什么不同?正如Alnitak和其他人指出的那样:
所以命名函数表达式有一些很好的属性,匿名函数表达式没有。但实际上似乎对这里应该发生的事情存在分歧。根据{{3}}:
箭头功能始终是匿名的
而MDN到this answer说:
“[从ES6开始]很多”匿名“函数表达式创建了带有名称的函数,这是各种现代JavaScript引擎在从上下文推断名称时非常聪明的事情......这遍布整个规范”< / p>
其他参考资料:
我发现处理此问题的最佳方法是使用Javascript - Precedence in hoisting。
答案 1 :(得分:4)
如果你写:
function a(x) { }
然后该函数被提升到封闭范围的顶部,并且a
在整个范围内的解析时立即可用。
然而,当你写:
var a = function a(x) { }
然后var a
在封闭范围内不会有定义的值,直到实际执行此行为止。
但是,在函数中,不同的 a
将作为函数本身的本地作用域引用存在。
使用let a = function ...
构造Babel与后一种形式更加一致,确保在运行时将a
分配给(命名)函数表达式,而不是使用解析时间函数声明。
答案 2 :(得分:2)
这似乎符合标准(12.14.4):
AssignmentExpression [In,Yield]:LeftHandSideExpression [?Yield] = AssignmentExpression [?In,?Yield]
1.如果LeftHandSideExpression既不是ObjectLiteral也不是ArrayLiteral,那么
一个。让lref成为评估LeftHandSideExpression的结果 湾ReturnIfAbrupt(LREF)。
C。让rref成为评估AssignmentExpression的结果 d。设rval为GetValue(rref) 即如果LeftHandSideExpression的IsAnonymousFunctionDefinition(AssignmentExpression)和IsIdentifierRef都为true,那么
I.让hasNameProperty为HasOwnProperty(rval,“name”) II。 ReturnIfAbrupt(hasNameProperty)。
III。如果hasNameProperty为false,则执行SetFunctionName(rval,GetReferencedName(lref))。
因此,每当评估 未命名函数表达式 到 命名标识符 的评估时,该功能name应设置为标识名称。
Babel遵循此过程,并生成兼容的ES5实现
Chrome(v46.0.2490.71,V8引擎...)不遵循此流程,在这种情况下name
等于''
。
至于问题本身......
在Javascript中,何时需要将命名函数分配给变量?
答案是从不。由开发人员决定是否/何时使用命名函数。决定归结为对名称的特定需求(例如“字符串化”函数时)或调试需求(更好的堆栈跟踪......)。