如何在ES2015中编写命名箭头函数?

我有一个函数,我正在尝试将其转换为ES6中的新箭头语法。它是一个命名函数:

function sayHello(name) {
    console.log(name + ' says hello');
}

有没有办法在没有var语句的情况下给它一个名字:

var sayHello = (name) => {
    console.log(name + ' says hello');
}

显然,我只能在定义它之后使用这个函数。如下所示:

sayHello = (name) => {
        console.log(name + ' says hello');
    }

ES6中是否有新的方法来做到这一点?


答案 1

如何在ES2015中编写命名箭头函数?

你可以按照你在问题中排除的方式去做:你把它放在赋值或属性初始值设定项的右侧,其中变量或属性名称可以被JavaScript引擎合理地用作名称。没有其他方法可以做到这一点,但这样做是正确的,并且完全被规范所覆盖。

根据规范,此函数具有真实名称:sayHello

var sayHello = name => {
    console.log(name + ' says hello');
};

这当前在赋值运算符>运行时语义:评估中定义,它执行抽象的命名评估操作(当前步骤 1.c.i)。(通过将鼠标悬停在标题中的 NamedEvalution 上并单击“引用”,您可以看到这适用于任何地方。(以前,在ES2019之前,Assignment Operators > Runtime Semantics: Evaluation使用抽象的SetFunctionName操作,步骤1.e.iii,但在ES2019之后,这个规范抽象被NameEdEvalution所取代。

类似地,PropertyDefinitionEvaluation使用NameEdEvalution,因此给这个函数一个真正的名称:

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 及更高版本(以及带有实验标志的“Legacy” Edge 13 及以上版本,或 “Chromium” Edge 79 更高版本)上,当您运行它时,您将看到:

foo.name is: foo
Error
    at foo (http://stacksnippets.net/js:14:23)
    at http://stacksnippets.net/js:17:3

请注意和 。foo.name is: fooError...at foo

在 Chrome 50 及更早版本、Firefox 52 及更早版本以及没有实验性标志的 Legacy Edge 上,您会看到以下情况,因为它们没有该属性(尚未):Function#name

foo.name is: 
Error
    at foo (http://stacksnippets.net/js:14:23)
    at http://stacksnippets.net/js:17:3

请注意,中缺少该名称,但它显示在堆栈跟踪中。只是在函数上实际实现属性的优先级低于其他一些ES2015功能;Chrome和Firefox现在有它;Edge在旗帜后面有它,大概它不会在旗帜后面太久。foo.name is:name

显然,我只能在定义它之后使用它。

正确。箭头函数没有函数的函数声明语法,只有函数表达式语法,并且没有与旧式命名函数表达式 () 中的名称等效的箭头。因此,没有等效于: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"

您可以通过使用任何不使用命名评估的表达式来避免这种情况。可能最流行的方法来做这种事情是逗号运算符:

const example = (0, () => {});
//              ^^^−−−−−−−−−^
console.log(example.name); // ""

你可以有你想要的任何东西,它被评估然后扔掉,所以是一个受欢迎的选择。通过逗号运算符传递函数会断开赋值和函数表达式之间的直接链接,从而阻止 NamedEvaluation 提供函数的名称。(这类似于逗号运算符的其他著名用法,例如,在调用中不做 值的调用,或者 ,它执行 ,但不像往常一样在当前范围内。00example(0, object.example)()object.exampleobjectthis(0, eval)("code")eval

(感谢塞巴斯蒂安·西蒙(Sebastian Simon)在评论中提出这一点。


答案 2

不。箭头语法是匿名函数的缩写。匿名函数是匿名的。

命名函数使用关键字定义。function