这里实际上有两个不同的问题:
- 定义或表达函数的不同方式之间有什么区别?
- 为什么
let a = (x) => x + 1
会被转译成这样?
为了回答问题(2),我们需要理解问题(1)-- 这已经在SO和其他地方广泛讨论过。
问题1
让我们来看一下你提到的三种选择:
函数声明:
function a(x) { ... }
从语法上讲,这些函数必须始终以
function
(
参考)开头。它们在解析时被提升,并在本地作用域中创建一个命名函数。
(匿名)函数表达式:
var a = function (x) { ... }
var a
本身将在解析时进行提升,但在运行时直到执行此行之前它都是undefined
。
命名函数表达式:
var a = function a(x) { ... }
尽管语法看起来像是对一个函数声明进行赋值,但实际上这只是一个带有名称的函数表达式。我觉得这很令人困惑,但这就是语法。
函数声明和函数表达式之间的主要区别在于,使用声明,您可以执行以下操作:
a(1);
function a(x) { return x + 1; }
尝试使用函数表达式(命名或匿名)实现这一点会导致错误。
问题2
- 为什么let a = (x) => x + 1会被转换成这样?
我们将箭头函数 (x) => x + 1
赋值给一个块级作用域变量 let
,因此我们应该期望在运行时执行此行之后,才会定义 a
。这应该是一个函数表达式,而不是函数声明。
最后,为什么 let a = (x) => x + 1
被转换为命名函数表达式而不是匿名函数表达式?有什么区别吗?正如Alnitak和其他人指出的:
- 函数名称出现在调试器中,可以帮助调试。
- 命名函数定义内部的作用域具有对函数本身的引用。这允许递归和访问包含函数的属性。
所以所谓的“命名函数表达式”具有某些匿名函数表达式没有的优点。但实际上对于这里应该发生什么似乎存在分歧。根据
MDN:
箭头函数始终是匿名的
而
this answer对
Why use named function expressions?的回答则表示:
“[自ES6起]许多‘匿名’函数表达式创建具有名称的函数,这是由各种现代JavaScript引擎在从上下文推断名称方面非常聪明之前的先例... 这散布在规范中。”
其他参考资料:
我发现最好的方法是通过玩转 Babel REPL 来掌握这个。
x
的情况,您将使用x()
调用函数a
,因为a()
未定义基本上,独立行上的函数定义function lol(){}
将与var lol = function lol(){}
相同。 - Zorgatonea.name ='a'
,但并非所有浏览器都支持这一点。 - Felix Kling