ES2015で名前付き矢印関数を作成するにはどうすればよいですか?


204

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でこれを行う新しい方法はありますか?


3
矢印構文のポイントは、関数に名前を付けないためではありませんか?
AstroCB 2015年

64
必ずしもそうとは限りませんが、矢印関数は字句スコープを維持するため、字句スコープを持つ名前付き関数(スタックトレースに便利)を作成するための省略形があればかなり役に立ちます
Matt Styles

6
2番目のスニペットの何が問題になっていますか?
Bergi、2015

関数の本文内で割り当てられた名前を参照できます。varsayHello =(name)=> {console.log(sayHello); }; そして、再帰的な関数の場合、正確にそれを行うことがよくあります。非常に便利な例ではありませんが、引数を取得しないと自分自身を返す関数は次のとおりです。var sayHello =(name)=> name?console.log(name + 'はhello'と言います):sayHello; sayHello()( 'フランク'); //->「フランクはこんにちは」
Dtipson

4
質問のタイトルは、その内容に比べて非常に誤解招くものです。これは、矢印関数の名前の付け方(2番目のスニペット)を除外しているためです。
TJクロウダー2016年

回答:


211

ES2015で名前付き矢印関数を作成するにはどうすればよいですか?

これは、質問で除外した方法で行います。これは、割り当てまたはプロパティ初期化子の右側に配置します。変数またはプロパティ名は、JavaScriptエンジンによって名前として合理的に使用できます。何もありませんその他のそれを行うための方法は、それをやってすることは正しいと完全仕様で覆われています。

仕様によると、この関数には本当の名前がありますsayHello

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

これは、代入演算子>ランタイムセマンティクス:抽象操作を呼び出す評価で定義されています。SetFunctionNameを呼び出します(その呼び出しは現在ステップ1.e.iiiにあります)。

同様に、ランタイムセマンティクス:PropertyDefinitionEvaluationが呼び出されるSetFunctionNameため、この関数に本当の名前が付けられます。

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

最近のエンジンは、そのようなステートメントの関数の内部名をすでに設定しています。Edgeには、nameランタイムフラグの背後にある関数インスタンスのように、それを使用可能にするビットがまだあります。

たとえば、Chromeまたは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以降)では、それを実行すると次のように表示されます。

foo.nameは:foo
エラー
    at foo(http://stacksnippets.net/js:14:23)
    http://stacksnippets.net/js:17:3

注意してくださいfoo.name is: fooError...at foo

Chrome 50以前、Firefox 52以前、および実験的フラグのないEdgeでは、Function#name(まだ)プロパティがないため、代わりにこれが表示されます。

foo.nameは: 
エラー
    at 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

あなたはそれを2つの表現に分解する必要があります(とにかくそれをするべきだと私は主張します)

let 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((() => {
    let 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

それはすばらしいことではありませんが、1つの式ラッパーが確実に必要な場合は機能します。


(古いエンジンのように)名前が設定されないようにするにはどうすればよいですか?
trusktr 2018年

1
@trusktr:なぜあなたがしたいのかはわかりませんが、それを防ぎたいのであれば、上記のことはしないでください。たとえばlet f = () => { /* do something */ };、関数に名前を割り当てますが、let g = (() => () => { /* do something */ })();そうではありません。
TJクラウダー2018年

それは私がやったことです。クラス継承ライブラリのユーザーが考える必要のない内部変数の名前を持つよりも、クラス継承ライブラリによって生成される匿名クラスを匿名にしたいのですが、エンドユーザーに名前を表示してもらいたいのですが彼らがクラスの名前を提供した場合のみ。(github.com/trusktr/lowclass
trusktr

4
@trusktr:彼らが作った1つの例外はあなたの目的に合うかもしれません:既存のオブジェクトのプロパティに関数を割り当てた場合、名前は設定されo.foo = () => {};ません:関数に名前を付けません。これ、情報漏えいを防ぐための意図的なものです。
TJクラウダー2018年

86

いいえ。矢印の構文は、無名関数の省略形です。匿名関数は匿名です。

名前付き関数はfunctionキーワードで定義されます。


16
@DenysSéguretで述べたように、は無名関数の省略形ではありません。ハードバインドされた関数を取得します。変換された結果は、ここでbit.do/es2015-arrowで確認できます。これが何を意味するかがよくわかります
sminutoli

16
この答えの最初の単語は、OPが矢印関数の名前の付け方を除外したため、尋ねられた質問に対して正しいです。しかし、残りの答えは単に正しくありません。仕様で、抽象SetFunctionName演算が使用される場所を確認してください。名前付き関数(名前は)を、仕様と最新のエンジンの両方でlet a = () => {};定義します(表示するにはエラーをスローします)。それらはまだプロパティをサポートしていません(しかし、それは仕様にあり、最終的にはそこに到達します)。aname
TJクロウダー

4
@DenysSéguret:あなた 単純に名前を付けるができます。仕様に含まれています。これは、OPが質問で除外した方法で行います。これにより、(変数だけでなく)関数に真の名前が付けられます。
TJクラウダー2016

5
@TJCrowderその少しの情報、そしてあなたの役に立つ答えをありがとう。私はこの(非常に奇妙な)機能を知りませんでした。
DenysSéguret16年

4
この答えは正しくありません。下の@TJCrowderが質問に正しく回答しました
Drenai

44

「名前付き」と.nameは、アロー関数のプロパティを設定することを意味し、運がいいです。

矢印関数は代入式の右辺に定義されている場合、エンジンは左手側に名前を取り、矢印機能の設定するためにそれを使用します.name、例えば

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

sayHello.name //=== 'sayHello'

そうは言っても、あなたの質問はより「矢印関数を巻き上げることができますか?」その答えは、大昔の「いいえ」だと思います。


1
現在のバージョンのChromeでは、少なくともsayHello.nameはまだ ""です。すべての関数と同様に、sayHelloはオブジェクトなので、必要に応じて任意のプロパティを定義できます。「name」は読み取り専用であるため、書き込むことはできませんが、「Hello.my_name = "sayHello"」と言うことはできます。ただし、関数の本体内でそれを実行/参照することはできないため、それが何をもたらすのかはわかりません。
Dtipson

2
私は間違っていました:名前は直接変更可能ではありませんが、次のように構成できます:Object.defineProperty(sayHello、 'name'、{value: 'sayHello'})
Dtipson

1
「矢印関数が右側に定義されている場合[..]」これのソースは何ですか?スペックでは見つかりません。引用するための参照が必要です。
ガジュス

@Dtipson:これnameは、ES2015仕様で必要とされるすべての場所でプロパティを設定することを最新のエンジンがまだ実装していないためです。彼らはそれに到達します。これはChromeのコンプライアンスリストの最後の項目の1つであり、Chrome 50にもそれがありません(Chrome 51がついに登場します)。詳細。しかし、OPはこれを(奇妙に)行うことを明確に除外しました。
TJクロウダー2016年

この名前をtoStringで取得できますか?オーバーライドしてみましたが、関数本体にアクセスする方法がわかりません。
Qwerty、

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ファイルで、次のようにバベルローダーを更新しました。

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

6
これは、厳密には名前付きの矢印関数ではありません。これはコンストラクターでインスタンスメソッドを作成するためのショートカットです。ここでどのように関連しているのでしょうか。
Bergi、2015

こんにちは@Bergi、これが元の作者の意図であるかどうかはわかりませんが、オブジェクトと同じthisスコープを持つ名前付き関数を作成しようとしました。この手法を使用せず、適切なスコープが必要な場合は、クラスコンストラクターでそれを取り込む必要があります。this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this);
Hamish Currie、2015

8
ええと、constructor() { this.handleOptionsButtonClick = (e) => {…}; }あなたの答えのコードと完全に同等ですが、ES6で既に動作しているのと同じくらい簡単に使用できます。使用する必要はありません.bind
Bergi、2015

1
ところで、「名前付き関数」と「(インスタンス)メソッド」、「スコープ」と「thisコンテキスト」を混同していると思います
Bergi

1
@tdecs:はい、できます。ヨルクは間違っています。let a = () => {};という名前の矢印関数を定義しaます。詳細
TJクラウダー2016年

0

実際には、矢印関数に名前を付ける1つの方法のように見えます(少なくとも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);
}

ここに画像の説明を入力してください


理論的にはfn('yourName', ()=>{})、100%正しい矢印関数のセマンティクスを維持できるバベルマクロを作成できますが、「名前付き矢印関数構文」用のバベルプラグインを作成することもできますfn yourName() => {}。これらのどちらでも、上のコードにコンパイルされます。名前付き矢印はBADA55
Devin G Rhode

-1

名前付き矢印関数を記述するために、次の例を実行できます。ここでは、LoginClassという名前のクラスがあり、このクラス内に、 class LoginClass という名前のfunctionという名前の矢印を書き込みましたsuccessAuth{

    constructor() {

    }

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

    }

}

1
投稿するコードに解答として説明を追加することをお勧めします。これにより、訪問者がこれが良い解答である理由を理解しやすくなります。
abarisone

これはOPが彼がやりたくないと言ったことを実行し、ステージ2でのみであり、おそらくES2017を作成するつもりはないこの提案に依存しています(しかし、私はES2018を作成する可能性が高く、トランスパイラーがそれをサポートしています数ヶ月間)。また、以前のいくつかの回答を効果的に複製しますが、これは役に立ちません。
TJクラウダー2017

-2

これはES6です

ええ、あなたが求めているのは次のようなものだと思います:

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

私はこの例を試しましたが、うまくいきます。反対票を投じる正当な理由はありますか?この使用法は不要な副作用を引き起こしますか、それとも重要なポイントを見逃していますか?私の疑いを明確にするのにあなたの助けをいただければ幸いです。
FullMoon

@GaneshAdapa:反対票は、OPが彼/彼女がやりたくないと言ったことを正確に実行することを示唆しているためであると思います。
TJクラウダー2017年

-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();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.