「this」をアロー関数にバインドできますか?


133

ES6をしばらく試してみましたが、ちょっとした問題が発生しました。

私はアロー関数を使うのが本当に好きで、できる限りそれを使います。

ただし、バインドできないようです。

これが関数です:

var f = () => console.log(this);

これは、関数をバインドするオブジェクトです。

var o = {'a': 42};

そして、ここで私が結合する方法ですfo

var fBound = f.bind(o);

そして、私はただ電話することができますfBound

fBound();

これを出力します(oオブジェクト):

{'a': 42}

涼しい!美しい!それが機能しないことを除いて。oオブジェクトを出力する代わりに、オブジェクトを出力しwindowます。

だから私は知りたいです:あなたは矢印関数をバインドできますか?(もしそうなら、どうですか?)


上記のコードをGoogle Chrome 48とFirefox 43でテストしましたが、結果は同じです。


29
矢印関数の要点はthis、親スコープのを使用することです。
loganfsmyth 2015年

回答:


158

アロー関数で再バインド することはできませんthis。これは常に、それが定義されたコンテキストとして定義されます。this意味を持たせる必要がある場合は、通常の関数を使用する必要があります。

以下からのECMAScript 2015仕様

ArrowFunction内の引数、super、this、またはnew.targetへの参照は、字句的に囲まれた環境でバインディングに解決される必要があります。通常、これは直接囲んでいる関数の関数環境になります。


7
この回答の最初の文は間違っています。おそらく問題はバインディングとを混同しているためthisです。2つは関連していますが、同じではありません。this矢印関数の内部は、常にthis囲みスコープから「継承」します。それがアロー機能の特徴です。ただしbind、アロー関数の他のすべてのパラメーターは引き続き使用できます。ただじゃないthis
Stijn de Witt

54

完全にするために、矢印関数を再バインドできます、の意味を変更することはできませんthis

bind 関数の引数にはまだ値があります:

((a, b, c) => {
  console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()

ここで試してください:http : //jsbin.com/motihanopi/edit?js,console


1
this(もちろん、字句的に定義されている)参照せずに、(矢印)関数がバインドされているオブジェクトを検出または使用する方法はありますか?
Florrie

3
コンテキストに引数を使用します:((context)=> {someOtherFunction.apply(context)})。bind(willBeIgnored、context)()
cvazac

13

MDNから:

矢印関数式は、関数式に比べて構文が短く、字句的にthis値をバインドします(独自のthis、arguments、super、またはnew.targetをバインドしません)。アロー関数は常に匿名です。

つまり、値をthis好きなようにバインドすることはできません。


6

何年もの間、js開発者はコンテキストバインディングに苦労し、なぜthisjavascript が変更されたのかと尋ねました。コンテキストバインディングと、thisjavascriptとthis他のほとんどのOOP言語の意味との違いにより、何年にもわたって混乱しました。

これらすべてが私に、なぜ、なぜ、なぜ尋ねるのかを導きます!アロー関数を再バインドしないのはなぜですか?このすべての問題と混乱を解決するために特別に作成され、関数のスコープを維持するためにbindcallまたはその他の方法を使用する必要がないように作成されたもの。

TL; DR

いいえ、矢印関数を再バインドすることはできません。


7
アロー関数はまず、より簡潔で高速な構文を提供するために作成されました。ラムダ計算を考えてください。関数型JSプログラマーの生活を困惑させるOO狂信者は、呼び出しコンテキストを指定する自由を奪う機会を手に入れました。
Marco Faustinelli、2017年

5
を使用しthisても機能しません。ラムダはである必要がありますarguments => output。外部コンテキストが必要な場合は、渡してください。の存在そのものがthis、OOパターンの言語へのすべてのシューホーニングを促進したものです。これがないと、「JavaScriptクラス」という言葉は聞いたことがないでしょう。
erich2k8

3
あなたはできるの矢印の機能を再バインドします。ただじゃないthis
Stijn de Witt

6

を使用bindthisて、矢印関数内の値を変更することはできません。ただし、古いarrow関数と同じことを行う新しい通常の関数を作成し、callまたはbindを使用しthisて通常どおり再バインドできます。

evalここで呼び出しを使用して、通常の関数として渡した矢印関数を再作成callし、別の関数で呼び出すために使用しますthis

var obj = {value: 10};
function arrowBind(context, fn) {
  let arrowFn;
  (function() {
    arrowFn = eval(fn.toString());
    arrowFn();
  }).call(context);
}
arrowBind(obj, () => {console.log(this)});


3
アロー関数を別のコンテキストにバインドする方法のこの例を共有していただきありがとうございます。将来の読者が解答を理解しやすくするために、おそらくコードを編集して、コードがどのようにそしてなぜ機能するかを説明できますか?
Florrie、

4

ES6の矢印関数がJavaScriptで「これ」を本当に解決するか

上記のリンクは、矢印関数thisbind, call, apply関数によって変化しないことを説明しています。

それは非常に素晴らしい例で説明されています。

これを実行しnode v4て、「期待される」動作を確認します。

this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){ 
    // bind the value of "this" on the method 
    // to try and force it to be what you want 
    this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar(); 

答えは、それ自体でより適切な情報を提供するために、あなたを要求し、サンプルコードや質問の編集されたバージョンのかもしれ
Jithin Scaria

//これをノードv4で実行して、「期待される」動作を確認しますthis.test = "attached to the module"; var foo = {test: "attached to a object"}; foo.method = function(name、cb){//メソッドの "this"の値をバインドします//必要な値にしようと強制しますthis [name] = cb.bind(this); }; foo.method( "bar"、()=> {console.log(this.test);}); foo.bar();
Prithvi Raj Vuppalapati

ここで興味深いのは、これを試し、次にfoo.method( 'bar'、()=> {console.log(this.test);});を置き換えてもう一度試すことです。with foo.method( 'bar'、function(){console.log(this.test);}); -最初のバージョンは「モジュールに添付」のログを記録し、2番目は「オブジェクトに添付」のログを記録-矢印関数を使用した「これ」のより安定した処理を実際に好みます。さまざまなパターンを使用して他の効果を得ることができ、結果はより読みやすく予測可能なIMOです。
方法論医、


2

ショート、あなたは矢印関数をバインドすることはできませんが、以下を読んでください:

thisコンソールに印刷する下の矢印関数があるとします。

const myFunc = ()=> console.log(this);

したがって、これのクイックフィックスは通常の関数を使用することになるため、次のように変更します。

function myFunc() {console.log(this)};

次に、bindor callまたはapply:を使用して、任意の字句環境にバインドできます。

const bindedFunc = myFunc.bind(this);

の場合はそれを呼び出しますbind

bindedFunc();

を使用eval()してそれを行う方法もありますが、これは強くお勧めしません


function myFuncバインド可能である以外に、行動的には異なります。より近い一致になりますconst myFunc = function() {...}。evalを使用することの意味にも興味があります。これは、これまでに回答が共有されたとは思えないアプローチです。これがどのように行われるかを確認し、それが非常に推奨されない理由を読むのは興味深いでしょう。
フローリー

1

多分この例はあなたに役立ちます:

let bob = {
   _name: "Bob",
   _friends: ["stackoverflow"],
   printFriends:(x)=> {
      x._friends.forEach((f)=> {
         console.log(x._name + " knows " + f);
      });
   }
}

bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();


良いもの...穏やかに面白い
ALEKS
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.