※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。
こちらは、
【JavaScript】JavaScriptの 「 this」とは 2 (thisの問題点と解決策)
の記事の続きとなります。
##thisの問題点について 2
コールバック関数の中でthisを参照すると問題となる場合があります。
この場合の、対処法としてコールバック関数にアロー関数を使用します。
なぜ、コールバック関数の場合に、thisの参照が問題になるのかというと、コールバック関数内部のthisが呼び出し元を参照するからでした。
実は、この挙動は関数宣言により関数を定義した場合に起こる挙動で、アロー関数は別の挙動をします。
関数宣言の場合、暗黙的な引数として呼び出し元オブジェクトをthisとして受け取るのですが、アロー関数は、thisを受け取りません。
//関数宣言の場合
human1 = {
name: "Taro",
getName: function (x) { //暗黙的に呼び出元オブジェクト(human1)を仮引数xに渡す。(実際には()内は空欄)
this = x; //thisにx(human1)を格納。(実際にはこんな式はない)
}
}
console.log(human1.getName(human1)); //暗黙的に呼び出し元オブジェクトを引数に渡す。実際には()内は空欄
this = x; //thisにxを格納。
アロー関数には、暗黙的なこの挙動がありません。
下記は、関数宣言でコールバック関数が問題となるコードです。
"use strict";
const prefix = {
pre: "the",
addPre(strings) {
return strings.map(function (str) {
return this.pre + "-" + str;
});
}
};
prefix.addPre(["a", "b", "c"]);
// =>TypeError: Cannot read property 'pre' of undefined
これをコールバック関数をアロー関数で書き直してみます。
"use strict";
const prefix = {
pre: "the",
addPre(strings) {
return strings.map((str)=> {
return this.pre + "-" + str;
});
}
};
let result = prefix.addPre(["a", "b", "c"]);
console.log(result);
//[ 'the-a', 'the-b', 'the-c' ]
正しく出力されました。
このカラクリを見ていきます。
return strings.map((str)=> {
return this.pre + "-" + str;
});
アロー関数が、暗黙的にthisを受け取らないとするならばthisは、一体何を参照するのか。
これは、シンプルに**「this」**という変数として参照します。
当然、アロー関数内に let this = "taro"; みたにな定義文はないので、スコープチェーンを辿って、一つ上の階層へ探しにいきます。
この辺りの挙動は下記の記事を参照してください。
【JavaScript】JavaScriptにおけるクロージャーとは
今、addPre関数は、
prefix.addPre()
のプログラムにより、prefixオブジェクトから呼び出されています。
addPressメソッドの内部自体にはthisがないため、特に意識をしませんが、暗黙的にprefixをオブジェクトを、
thisとして受け取っています。
"use strict";
const prefix = {
pre: "the",
addPre(strings, x) { //暗黙的に仮引数xにprefixオブジェクトを格納)
let this = x; //暗黙的にthisにxを格納。
return strings.map((str)=> {
return this.pre + "-" + str;
});
}
};
let result = prefix.addPre(["a", "b", "c"]);
console.log(result);
つまり、アロー関数内のthisは、スコープチェーンを辿って、prefix内の暗黙的なthisを参照するのです。
当然、このthisにはprefixオブジェクトが格納されているので。
アロー関数内のthis.pre は prefix.preを参照し、 「"the"」が取得することができます。
このように、アロー関数を用いることで、意識せずにコールバック関数内のthis問題を解決することができます。