fujjima’s blog

主に備忘録

JSのbind、及び`this`について理解を少し深める

bindそのものについて

JSのbindの用法を知り、「どういう時に使われるのか」が漠然とイメージできるようになりたかったため、概要と使われ方を調べた。

とりあえず以下のサイトのデモコードを自分なりにいじってどういう挙動なのかは調べた。

Function.prototype.bind() - JavaScript | MDN

const module = {
  a: 50,
  b: 30,
  text: 'this is test',
  showText: function(){
    return this.text;
  },
};

const moduleShow  = module.showText;
console.log(moduleShow);

// moduleから抜き出した関数にmodule自体をbindする
// moduleShow内のthis = bindされたmoduleとなる
// そのため、this.text = module.text、になる
const boundGetX = moduleShow.bind(module);
console.log(boundGetX());


その他、bindの概要、callとの違いについては下記の記事を見てイメージは出来た。 JavaScript thisの内容を指定する(bindメソッド) | ITSakura

ただ、こいつがどういう目的で使われるかは分からなかった。*1

単純に、関数内のthis(thisがない場合はbind内の第一引数にnullを指定する)を特定のものに設定する(=undefinedにしない)場合にbindを使う、という使い方でいいのだろうか。

アロー関数内でのthisの扱われ方とbindの比較

ここまで調べて、そういえばJSの通常関数とアロー関数ではthisの指すものが異なる、という話しを思い出した。

【JavaScript】アロー関数式を学ぶついでにthisも復習する話 - Qiita

JavaScript: 通常の関数とアロー関数の違いは「書き方だけ」ではない。異なる性質が10個ほどある。 - Qiita


両者のthisに関する違いとしては、アロー関数はthisを束縛し、通常関数はthisを束縛しない(=関数呼び出し元(レシーバ)をthisとする)という点である。

下記のコードを例に比較する。

  • 通常関数
this.name = "globalName";

// 通常関数
function showName() {
  console.log(this.name);
}

let arrowFunc = {
  name: "john",
  func: showName,
};

arrowFunc.func();
=> john

// bindを使った場合
showName.bind(arrowFunc)();
=> john

arrowFunc.func()の返り値がjohnとなっており、これはarrowFunc.nameの値であることが分かる。 このことから、arrowFunc.func()、つまりはarrowFunc.showName()のshowName内部のthisはarrowFunc(レシーバ)を指していたことが分かる。

  • アロー関数
this.name = "globalName";

// アロー関数
const showName = () => {
  console.log(this.name);
};

let arrowFunc = {
  name: "john",
  func: showName,
};

arrowFunc.func();
=> globalName

arrowFunc.func()の返り値が「globalName」となっている。これは最初に定義したthis.name = "globalName"のnameの値が表示されていることが分かる。 ここで、アロー関数内のthisについてのリファレンスを見てみる。

アロー関数自身は this を持ちません。レキシカルスコープの this 値を使います。つまり、アロー関数内の this 値は通常の変数検索ルールに従います。このためスコープに this 値がない場合、その一つ外側のスコープで this 値を探します。

アロー関数 - JavaScript | MDN


アロー関数であるshowNameが定義された際、関数内のthisは更に外側のthisを見ていたことになる。 今回Node上で上記コードを実行したため、thisとして定義されていたのは{name: "globalName"}だったため、showName関数内のconsole.logで表示されたthis.nameは、コードの最初に定義したthis.nameだった、ということになる。


ちなみにトップレベル、グローバルスコープあたりはここを参考にした。

JavaScriptのトップレベルスコープは常にグローバルスコープではなかった - Qiita

まとめ

改めてbind、通常関数とアロー関数それぞれでのthisの使い方を確認した。 通常関数とアロー関数の違いについては他にも色々あるが、一旦知りたいと思っていたことを確認することができた。

*1:こういったサンプルを見て、「じゃあこういうものにも応用できるな」と考えつく能力もプログラマに必要不可欠な能力だよな、と最近感じている