如何在 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 中有没有新的方法来做到这一点?

原文由 jhamm 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 571
2 个回答

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

你按照你在问题中排除的方式来做:你把它放在赋值或属性初始值设定项的右侧,其中变量或属性名称可以合理地用作 JavaScript 引擎的名称。没有 其他 方法可以做到这一点,但这样做是正确的,并且完全包含在规范中。 (它也适用于传统的匿名 function 表达式。)

根据规范,此函数有一个真实名称 sayHello

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

这当前在 赋值运算符 > 运行时语义:评估 中定义,它执行抽象的 NamedEvalution 操作(当前步骤 1.ci)。 (您可以通过将鼠标悬停在标题中的 NamedEvalution 上并单击“参考”来看到这适用的任何地方。)(以前,在 ES2019 之前, 赋值运算符 > 运行时语义:评估 使用 了抽象的 SetFunctionName 操作,步骤 1.e.iii,但在 ES2019 之后,此规范抽象被 NamedEvalution 取代。)

同样, PropertyDefinitionEvaluation 使用 NamedEvalution 并因此为该函数赋予了一个真实的名称:

 let o = {
    sayHello: (name) => {
        console.log(`${name} says hello`);
    }
};

现代引擎已经为这样的语句设置了函数的内部名称。

注意:要进行此名称推断,必须将函数表达式 直接 分配给目标。例如,这不会推断名称:

 const sayHello = (void 0, (name) => {
    console.log(name + ' says hello');
});
console.log(sayHello.name); // ""

那是因为函数表达式没有直接分配给 const ,它是另一个运算符的操作数(在这种情况下,逗号运算符,但对于 [say] true && (name) => { } )。

例如,在 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 是:foo
错误
    在富(http://stacksnippets.net/js:14:23)
    在 http://stacksnippets.net/js:17:3

注意 foo.name is: fooError...at foo

在 Chrome 50 及更早版本、Firefox 52 及更早版本以及没有实验标志的 Legacy Edge 上,你会看到这个,因为它们还没有 Function#name 属性(尚):

foo.name 是:
错误
    在富(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 。 (This is similar to other famous uses of the comma operator, like (0, object.example)() which calls object.example without making object the value of this within呼叫,或 (0, eval)("code") ,它执行 eval ,但不像通常那样在当前范围内。)

(感谢 Sebastian Simon 在评论中提出这一点。)

原文由 T.J. Crowder 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

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

原文由 Jörg W Mittag 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏