おまじないとして使ってしまいがちなbind(this)をちゃんと理解するために、
O'REILLY「初めてのJavaScript 第3版 ES2015(ES6)対応」を読み返してみたので、
自分用のメモとして記事に残してみる。
自分用と言わず、同じような疑問を持っている人の助けになったら嬉しいです。
最近Reactを扱うことがあって、なんでそんなに関数をbindしまくるんだっけ?と
思ったのが今回本を読み返したモチベーション。
ネット上で解説している記事の多くは、サンプルコードを理解するのに一苦労でわかりにくい。
以下のコードが超シンプルかつわかりやすいので紹介する。
下記のようなオンラインコンソールでコードを動かしてみると理解が深まるかと。
https://stephengrider.github.io/JSPlaygrounds/
コードの引用元:上記のO'REILLY
###うまくいかないコード
オブジェクトobj.name
に定義した文字列を反転させるサンプルコード。
動かしてみると、getReverseName()
内のthis
が怒られてしまうことがわかる。
原因は、最終行でobj.greetBackwards()
を呼び出すときは this
はobj
と紐付けられている一方で、greetBackwards
の内側からgetReverseName
を呼び出すときはthis
が別物となってしまうことにある。
const obj = {
name : 'hello world',
greetBackwards : function() {
function getReverseName() {
let nameBackwards = '';
for(let i = this.name.length - 1; i >= 0; i--) { //ココのthisが怒られる
nameBackwards += this.name[i]; //ココのthisも怒られる
}
return nameBackwards;
}
return getReverseName();
}
}
console.log(obj.greetBackwards()); //表示されない
###うまくいくコード1(self = thisを使用)
これを解消する手段として、this
を別の変数に代入してあげる方法が挙げられる。
self
やthat
を使うのがポピュラーとのこと。
const obj = {
name : 'hello world',
greetBackwards : function() {
const self = this; //thisを別の変数に置き換える
function getReverseName() {
let nameBackwards = '';
for(let i = self.name.length - 1; i >= 0; i--) { //self.nameとする
nameBackwards += self.name[i]; //self.nameとする
}
return nameBackwards;
}
return getReverseName();
}
}
console.log(obj.greetBackwards()); //dlrow olleh
###うまくいくコード2(bindを使用)
別の手段として、greetBackwards
の中でgetReverseName
を呼び出す際に
.bind(this)
を付与して、getReverseNameのthis
を objのthis
として呼び出すように指示する。
const obj = {
name : 'hello world',
greetBackwards : function() {
function getReverseName() {
let nameBackwards = '';
for(let i = this.name.length - 1; i >= 0; i--) {
nameBackwards += this.name[i];
}
return nameBackwards;
}
return getReverseName.bind(this)(); //ココにbind追加
}
}
console.log(obj.greetBackwards());
###どっちが良いか
個人的にはself = this
の方が読みやすいので好き。
どちらが一般的によく使われるのか調べていたら、
こちらの記事で考察してるのを見付けた。とっても分かりやすい。
https://www.deep-rain.com/programming/javascript/807