web-dev-qa-db-ja.com

ES6矢印関数とFunction.prototype.bindでバインドされた関数の違い(ある場合)は何ですか?

ES6では、次の2つの機能は非常にほぼ同一であると思われます。

function () {
  return this;
}.bind(this);

() => {
  return this;
};

最終的な結果は同じようです。矢印関数は、thisコンテキストが作成されたthisと同じ値にバインドされたJavaScript関数オブジェクトを生成します。

明らかに、一般的な意味では、Function.prototype.bindは矢印関数よりも柔軟性があります。ローカルthis以外の値にバインドできます。また、関数のthisをいつでもバインドできます。 。ただし、bind自体が矢印関数とどのように異なるかを尋ねているのではなく、bindthisをすぐに呼び出すことと矢印関数がどのように異なるかを尋ねています。

ES6の2つのコンストラクトに違いはありますか?

46
Alexis King

(重要な)違いはありません。

まあ、大丈夫、それは少し時期尚早です。矢印関数に固有の3つのtiny違いがあります。

  1. 矢印関数はnewで使用できません。

    これは、もちろん、それらがprototypeプロパティを持たず、古典的に着想を得た構文でオブジェクトを作成するために使用できないことを意味します。

    new (() => {}) // TypeError: () => {} is not a constructor
    

    ただし、これはおそらく最適です。newの動作方法は、バインドされた関数ではあまり意味がありません。

  2. 矢印関数は、通常のJavaScript関数がアクセスできる特別なargumentsオブジェクトにアクセスできません。

    (() => arguments)(1, 2, 3) // ReferenceError: arguments is not defined
    

    これはおそらくもう少しの落とし穴です。おそらく、これはJavaScriptのその他の奇妙な点の1つを取り除くためです。 argumentsオブジェクトはそれ自身の特別な獣です 、そして奇妙な振る舞いを持っているので、投げられたのは驚くことではありません。

    代わりに、ES6には魔法の隠し変数なしで同じことを達成できるスプラットがあります。

    ((...args) => args)(1, 2, 3) // [1, 2, 3]
    
  3. 矢印関数には独自の new.target プロパティ、new.target含まれる関数の存在する場合。

    これは、矢印関数の「魔法のように」導入された値を削除する他の変更と一致しています。上記のように、とにかくnewで矢印関数を使用できないことを考えると、この特定の変更は特に明白です。

それ以外の場合、矢印は意味的にバインドされた関数に似ています。追加の荷物を持ち歩く必要がなく、最初に通常の関数から変換する必要がないため、矢印のパフォーマンスが向上する可能性がありますが、動作はまったく同じです。

34
Alexis King

いくつかの違いがあります。

  • 矢印関数は構築できません。矢印関数とバインド関数の両方に_.prototype_プロパティがありませんが、前者はnewで呼び出されたときに例外をスローしますが、後者はバインドされた値を無視し、ターゲット関数を新しいインスタンスのコンストラクタ(ただし、部分的に適用されたバインドされた引数)。

    _function F() {}
    var f = () => {},
        boundF = F.bind({});
    console.log(new boundF(), new boundF instanceof F) // {}, true
    console.log(new f) // TypeError
    _
  • 矢印関数には、字句arguments、_new.target_、およびsuperもあります(字句thisだけではありません)。矢印関数の呼び出しはこれらのいずれも初期化せず、矢印関数が定義された関数から継承されます。バインドされた関数では、ターゲット関数のそれぞれの値を参照します。

  • 矢印関数は、実際にはthis値をバインドしません。むしろ、それらは持っておらず、thisを使用すると、レキシカルスコープの変数名のように検索されます。これにより、thisがまだ使用可能でないときに矢印関数を遅延定義することができます。

    _class X extends Object {
        constructor() {
             var f = () => this, // works
                 boundF = function(){ return this; }.bind(this);
    //                                                    ^^^^ ReferenceError
             super(); // initialises `this`
             console.log(f(), f() == this); // {}, true
        }
    }
    new X;
    _
  • 矢印関数をジェネレーター関数にすることはできません(ただし、ジェネレーターを返すことはできます)。ジェネレーター関数で.bind()を使用できますが、矢印関数を使用してこれを表現する方法はありません。

28
Bergi

もう1つ微妙な違いがあります。

=>の直後の{}中括弧を省略することにより、矢印関数は 'return'キーワードを使用せずに値を返すことができます。

var f=x=>x;           console.log(f(3));  // 3
var g=x=>{x};         console.log(g(3));  // undefined
var h=function(x){x}; console.log(h(3));  // undefined
var i=x=>{a:1};       console.log(i(3));  // undefined
var j=x=>({a:1});     console.log(j(3));  // {a:1}
5
Chong Lip Phang