JSのbind、及び`this`について理解を少し深める
<h4>bindそのものについて</h4>
<p>JSのbindの用法を知り、「どういう時に使われるのか」が漠然とイメージできるようになりたかったため、概要と使われ方を調べた。</p>
<p>とりあえず以下のサイトのデモコードを自分なりにいじってどういう挙動なのかは調べた。</p>
<p><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">Function.prototype.bind() - JavaScript | MDN</a></p>
<pre class="code lang-javascript" data-lang="javascript" data-unlink><span class="synStatement">const</span> module = <span class="synIdentifier">{</span>
a: 50,
b: 30,
text: <span class="synConstant">'this is test'</span>,
showText: <span class="synIdentifier">function</span>()<span class="synIdentifier">{</span>
<span class="synStatement">return</span> <span class="synIdentifier">this</span>.text;
<span class="synIdentifier">}</span>,
<span class="synIdentifier">}</span>;
<span class="synStatement">const</span> moduleShow = module.showText;
console.log(moduleShow);
<span class="synComment">// moduleから抜き出した関数にmodule自体をbindする</span>
<span class="synComment">// moduleShow内のthis = bindされたmoduleとなる</span>
<span class="synComment">// そのため、this.text = module.text、になる</span>
<span class="synStatement">const</span> boundGetX = moduleShow.bind(module);
console.log(boundGetX());
</pre>
<p><br></p>
<p>その他、bindの概要、callとの違いについては下記の記事を見てイメージは出来た。
<a href="https://itsakura.com/js-bind">JavaScript thisの内容を指定する(bindメソッド) | ITSakura</a></p>
<p>ただ、こいつがどういう目的で使われるかは分からなかった。<a href="#f-81413229" name="fn-81413229" title="こういったサンプルを見て、「じゃあこういうものにも応用できるな」と考えつく能力もプログラマに必要不可欠な能力だよな、と最近感じている">*1</a></p>
<p>単純に、関数内のthis(thisがない場合はbind内の第一引数にnullを指定する)を特定のものに設定する(=undefinedにしない)場合にbindを使う、という使い方でいいのだろうか。</p>
<h4>アロー関数内でのthisの扱われ方とbindの比較</h4>
<p>ここまで調べて、そういえばJSの通常関数とアロー関数ではthisの指すものが異なる、という話しを思い出した。</p>
<p><a href="https://qiita.com/mejileben/items/69e5facdb60781927929">【JavaScript】アロー関数式を学ぶついでにthisも復習する話 - Qiita</a></p>
<p><a href="https://qiita.com/suin/items/a44825d253d023e31e4d">JavaScript: 通常の関数とアロー関数の違いは「書き方だけ」ではない。異なる性質が10個ほどある。 - Qiita</a></p>
<p><br></p>
<p>両者の<code>this</code>に関する違いとしては、アロー関数は<code>this</code>を束縛し、通常関数は<code>this</code>を束縛しない(=関数呼び出し元(レシーバ)をthisとする)という点である。</p>
<p>下記のコードを例に比較する。</p>
<ul>
<li>通常関数</li>
</ul>
<pre class="code lang-javascript" data-lang="javascript" data-unlink>
<span class="synIdentifier">this</span>.name = <span class="synConstant">"globalName"</span>;
<span class="synComment">// 通常関数</span>
<span class="synIdentifier">function</span> showName() <span class="synIdentifier">{</span>
console.log(<span class="synIdentifier">this</span>.name);
<span class="synIdentifier">}</span>
<span class="synIdentifier">let</span> arrowFunc = <span class="synIdentifier">{</span>
name: <span class="synConstant">"john"</span>,
func: showName,
<span class="synIdentifier">}</span>;
arrowFunc.func();
=> john
<span class="synComment">// bindを使った場合</span>
showName.bind(arrowFunc)();
=> john
</pre>
<p><code>arrowFunc.func()</code>の返り値が<code>john</code>となっており、これはarrowFunc.nameの値であることが分かる。
このことから、<code>arrowFunc.func()</code>、つまりは<code>arrowFunc.showName()</code>のshowName内部のthisはarrowFunc(レシーバ)を指していたことが分かる。
<br></p>
<ul>
<li>アロー関数</li>
</ul>
<pre class="code lang-javascript" data-lang="javascript" data-unlink>
<span class="synIdentifier">this</span>.name = <span class="synConstant">"globalName"</span>;
<span class="synComment">// アロー関数</span>
<span class="synStatement">const</span> showName = () => <span class="synIdentifier">{</span>
console.log(<span class="synIdentifier">this</span>.name);
<span class="synIdentifier">}</span>;
<span class="synIdentifier">let</span> arrowFunc = <span class="synIdentifier">{</span>
name: <span class="synConstant">"john"</span>,
func: showName,
<span class="synIdentifier">}</span>;
arrowFunc.func();
=> globalName
</pre>
<p><code>arrowFunc.func()</code>の返り値が「globalName」となっている。これは最初に定義した<code>this.name = "globalName"</code>のnameの値が表示されていることが分かる。
ここで、アロー関数内のthisについてのリファレンスを見てみる。</p>
<blockquote><p>アロー関数自身は this を持ちません。レキシカルスコープの this 値を使います。つまり、アロー関数内の this 値は通常の変数検索ルールに従います。このためスコープに this 値がない場合、その一つ外側のスコープで this 値を探します。</p></blockquote>
<p><a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this">アロー関数 - JavaScript | MDN</a></p>
<p><br></p>
<p>アロー関数である<code>showName</code>が定義された際、関数内のthisは更に外側のthisを見ていたことになる。
今回Node上で上記コードを実行したため、thisとして定義されていたのは<code>{name: "globalName"}</code>だったため、<code>showName</code>関数内のconsole.logで表示されたthis.nameは、コードの最初に定義したthis.nameだった、ということになる。</p>
<p><br></p>
<p>ちなみにトッ<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%EC%A5%D9">プレベ</a>ル、グロー<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D0%A5%EB%A5%B9">バルス</a>コープあたりはここを参考にした。</p>
<p><a href="https://qiita.com/qeema/items/0b7e2ff4e33703a42a40">JavaScriptのトップレベルスコープは常にグローバルスコープではなかった - Qiita</a></p>
<h4>まとめ</h4>
<p>改めて<code>bind</code>、通常関数とアロー関数それぞれでのthisの使い方を確認した。
通常関数とアロー関数の違いについては他にも色々あるが、一旦知りたいと思っていたことを確認することができた。</p>
<div class="footnote">
<p class="footnote"><a href="#fn-81413229" name="f-81413229" class="footnote-number">*1</a><span class="footnote-delimiter">:</span><span class="footnote-text">こういったサンプルを見て、「じゃあこういうものにも応用できるな」と考えつく能力も<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%D7%A5%ED%A5%B0%A5%E9%A5%DE">プログラマ</a>に必要不可欠な能力だよな、と最近感じている</span></p>
</div>