如何在 ES2015 中编写命名箭头函数?
你按照你在问题中排除的方式来做:你把它放在赋值或属性初始值设定项的右侧,变量或属性名称可以合理地用作 JavaScript 引擎的名称。没有其他方法可以做到这一点,但这样做是正确的,并且完全包含在规范中。
根据规范,这个函数有一个真实的名字,sayHello
:
var sayHello = name => {
console.log(name + ' says hello');
};
这当前在赋值运算符 > 运行时语义:评估中定义,它执行抽象的NamedEvalution操作(当前步骤 1.ci)。(您可以通过将鼠标悬停在标题中的 NamedEvalution 上并单击“参考”来查看此适用的任何地方。)(以前,在 ES2019 之前,赋值运算符 > 运行时语义:评估使用了抽象的SetFunctionName操作,步骤 1.e.iii,但是在 ES2019 之后,这个规范抽象被 NamedEvalution 取代了。)
类似地,PropertyDefinitionEvaluation使用 NamedEvalution 并因此给这个函数一个真实的名字:
let o = {
sayHello: name => {
console.log(`${name} says hello`);
}
};
现代引擎已经为这样的语句设置了函数的内部名称。
例如,在 Chrome、Edge(基于 Chromium,v79 或更高版本)或 Firefox 中,打开 Web 控制台,然后运行以下代码段:
"use strict";
let foo = () => { throw new Error(); };
console.log("foo.name is: " + foo.name);
try {
foo();
} catch (e) {
console.log(e.stack);
}
在 Chrome 51 及更高版本和 Firefox 53 及更高版本(以及带有实验标志的“传统”Edge 13 及更高版本,或“Chromium”Edge 79 及更高版本)上,当您运行它时,您将看到:
foo.name 是: foo
错误
在 foo (http://stacksnippets.net/js:14:23)
在 http://stacksnippets.net/js:17:3
注意foo.name is: foo
和Error...at foo
。
在 Chrome 50 及更早版本、Firefox 52 及更早版本以及没有实验标志的 Legacy Edge 上,您会看到这一点,因为它们还没有该Function#name
属性:
foo.name 是:
错误
在 foo (http://stacksnippets.net/js:14:23)
在 http://stacksnippets.net/js:17:3
需要注意的是名字是从丢失foo.name is:
,但它是在堆栈跟踪中。只是实际在函数上实现name
属性的优先级低于其他 ES2015 特性;Chrome 和 Firefox 现在拥有它;Edge 有它在旗帜后面,大概它不会在旗帜后面太久了。
很明显,我只能在定义之后才能使用这个函数
正确的。箭头函数没有函数声明语法,只有函数表达式语法,并且没有与旧式命名函数表达式 ( var f = function foo() { };
) 中的名称等效的箭头。所以没有等价于:
console.log(function fact(n) {
if (n < 0) {
throw new Error("Not defined for negative numbers");
}
return n == 0 ? 1 : n * fact(n - 1);
}(5)); // 120
你必须把它分成两个表达式(我认为你应该这样做):
const fact = n => {
if (n < 0) {
throw new Error("Not defined for negative numbers.");
}
return n == 0 ? 1 : n * fact(n - 1);
};
console.log(fact(5));
当然,如果你必须把它放在需要单个表达式的地方,你总是可以......使用箭头函数:
console.log((() => {
const fact = n => {
if (n < 0) {
throw new Error("Not defined for negative numbers.");
}
return n == 0 ? 1 : n * fact(n - 1);
};
return fact(5);
})()); // 120
我不是说这很漂亮,但如果您绝对需要一个单一的表达式包装器,它就可以工作。
旁注:如果您不希望函数从您分配给的标识符中获取其名称怎么办?也就是说,假设你不希望example.name
是"example"
在这里吗?
const example = () => {};
console.log(example.name); // "example"
您可以通过使用任何不使用 NamedEvaluation 的表达式来避免它。可能最流行的做这种事情的方法是逗号运算符:
const example = (0, () => {});
// ^^^−−−−−−−−−^
console.log(example.name); // ""
在0
你想有可以是任何东西,它的评估,然后扔掉所以0
是一个受欢迎的选择。通过逗号运算符传递函数会中断赋值和函数表达式之间的直接链接,从而阻止 NamedEvaluation 提供example
函数的名称。(这类似于逗号操作符,像其他著名用途(0, object.example)()
这就要求object.example
没有做出object
valuethis
的通话中,或者(0, eval)("code")
,它确实的eval
,但不是在目前的范围,因为它通常会。)
(感谢Sebastian Simon在评论中提出这一点。)