238

我有一个函数,我试图将其转换为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中是否有新的方法可以做到这一点?

4

9 回答 9

261

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

您按照您在问题中排除的方式进行操作:将其放在赋值或属性初始化程序的右侧,其中变量或属性名称可以合理地用作 JavaScript 引擎的名称。没有其他方法可以做到这一点,但这样做是正确的,并且完全被规范所涵盖。

根据规范,这个函数有一个真实的名字,sayHello

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

这目前在Assignment Operators > Runtime Semantics:Evaluation中定义,它执行抽象的NamedEvalution操作(当前步骤 1.ci)。(您可以通过将鼠标悬停在标题中的 NamedEvalution 上并单击“References”来查看适用的任何地方。)(之前,在 ES2019 之前,Assignment Operators > Runtime Semantics:Evaluation使用了抽象的 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 及更高版本(以及带有实验标志的“Legacy”Edge 13 及更高版本,或“Chromium”Edge 79 及更高版本)上,当你运行它时,你会看到:

foo.name 是:foo
错误
    在 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 是:
错误
    在 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 产生objectthis的调用,或者(0, eval)("code"),它执行一个eval,但不像通常那样在当前范围内。)

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

于 2016-05-27T16:47:34.743 回答
87

不。箭头语法是匿名函数的简写形式。匿名函数是匿名的。

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

于 2015-01-16T05:00:39.647 回答
49

如果通过“命名”,您的意思是您希望.name设置箭头函数的属性,那么您很幸运。

如果在赋值表达式的右侧定义了箭头函数,引擎将采用左侧的名称并使用它来设置箭头函数的.name,例如

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

sayHello.name //=== 'sayHello'

话虽如此,您的问题似乎更多的是“我可以得到一个箭头功能来提升吗?”。恐怕这个问题的答案是“不”。

于 2015-07-21T16:05:13.283 回答
0

看来这将在 ES7 中成为可能: https ://babeljs.io/blog/2015/06/07/react-on-es6-plus#arrow-functions

给出的例子是:

class PostInfo extends React.Component {
  handleOptionsButtonClick = (e) => {
    this.setState({showOptionsModal: true});
  }
}

ES6 箭头函数的主体与围绕它们的代码共享相同的词法 this ,由于 ES7 属性初始化器的作用域方式,这可以得到我们想要的结果。

请注意,要使用 babel,我需要启用最具实验性的 ES7 阶段 0 语法。在我的 webpack.config.js 文件中,我更新了 babel 加载器,如下所示:

{test: /\.js$/, exclude: /node_modules/, loader: 'babel?stage=0'},
于 2015-07-09T02:58:19.520 回答
0

实际上,命名箭头函数的一种方法(至少从 chrome 77 开始......)是这样做的:

"use strict";
let fn_names = {};
fn_names.foo = () => { throw new Error(); };
console.log("foo.name is: " + foo.name);
try {
  foo();
} catch (e) {
  console.log(e.stack);
}

在此处输入图像描述

于 2019-09-20T21:35:41.947 回答
-1

为了编写命名箭头函数,您可以查看下面的示例,其中我有一个名为 LoginClass 的类,在这个类中我写了一个名为 function 的箭头,命名为successAuth class LoginClass {

    constructor() {

    }

    successAuth = (dataArgs)=> { //named arow function

    }

}
于 2016-07-12T10:05:01.707 回答
-1

正如Jörg所说,箭头函数不能命名。

如果您需要一个名称以获得更好的调用堆栈(变量名称,如const foo ...其他答案中不会出现在调用堆栈中)并且您不想使用函数关键字,请使用对象。

export const baz = {
    foo(bar) {
        alert(`I am in a ${bar}!`);
    }
}

基本上,从可读性的角度来看,导入后它会更好:

baz.foo('bar') 
// vs
foo('bar') // could look like a local function
于 2021-02-09T11:51:14.143 回答
-2

这是 ES6

是的,我认为你所追求的是这样的:

const foo = (depth) => {console.log("hi i'm Adele")}
foo -> // the function itself
foo() -> // "hi i'm Adele"
于 2016-01-24T01:38:24.873 回答
-2

您可以跳过函数部分和箭头部分来创建函数。例子:

 class YourClassNameHere{

   constructor(age) {
     this.age = age;
   }

   foo() {
     return "This is a function with name Foo";
   }

   bar() {
     return "This is a function with name bar";
   }

 }

let myVar = new YourClassNameHere(50);
myVar.foo();
于 2017-12-08T15:47:37.547 回答