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

How do I write a named arrow function in 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 中有没有新的方法来做到这一点?

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

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

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});
  }
}

The body of ES6 arrow functions share the same lexical this as the code that surrounds them, which gets us the desired result because of the way that ES7 property initializers are scoped.

请注意,为了使它与 babel 一起工作,我需要启用最具实验性的 ES7 stage 0 语法。在我的 webpack.config.js 文件中,我像这样更新了 babel 加载器:

{test: /\.js$/, exclude: /node_modules/, loader: 'babel?stage=0'},

如果'named',你的意思是你想要设置箭头函数的.name 属性,那么你很幸运。

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

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

sayHello.name //=== 'sayHello'

话说回来,你的问题好像比较'can I get an arrow function to hoist?'。恐怕那个问题的答案是一个大问题 "no"。

这是 ES6

是的,我想你想要的是这样的:

const foo = (depth) => {console.log("hi i'm Adele")}
foo -> // the function itself
foo() -> // "hi i'm Adele"

How do I write a named arrow function in ES2015?

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

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

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

目前在 Assignment Operators > Runtime Semantics: Evaluation where it does the abstract NamedEvalution operation (currently step 1.c.i). (You can see everywhere this applies by hovering your mouse over NamedEvalution in the header there and clicking "References".) (Previously, before ES2019, Assignment Operators > Runtime Semantics: Evaluation used the abstract SetFunctionName operation 步骤 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 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

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

Obviously, I can only use this function after I have defined it

正确。箭头函数没有 f​​unction declaration 语法,只有 function expression 语法,并且没有与旧式命名函数中的名称等效的箭头表达式(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 是一个流行的选择。通过逗号运算符传递函数会破坏赋值和函数表达式之间的直接 link,从而阻止 NamedEvaluation 为函数提供名称 example。 (这类似于逗号运算符的其他著名用法,例如 (0, object.example)() 调用 object.example 而没有 使 object 成为 [=33= 的值] 在调用中,或 (0, eval)("code"),它执行 eval,但不像通常那样在当前范围内。)

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

为了编写命名箭头函数,您可以参考下面的示例,其中我有一个名为 LoginClass 的 class 并且在这个 class 中我写了一个 箭头命名函数,名为 successAuth class 登录类 {

    constructor() {

    }

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

    }

}

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

 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();

实际上,命名箭头函数的一种方法(至少从 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);
}

所述,箭头函数无法命名。

如果您需要一个名称以便拥有更好的调用堆栈(变量名称,例如其他答案中的 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