この記事について
初学者の私にとって、JavaScritpのthisキーワードにかなり混乱してしまうので、
とりあえず関数を中心にthisについてまとめておく。
Thisを関数やメソッドに使うと
メソッド
thisが直感的にわかるメソッドの例から。
メソッドでのthisキーワードは、呼び出し元のオブジェクト(apple)を参照しますね。
なのでapple.priceである150を使用することができます。
const apple = {
price: 150,
calcPrice: function() {
this.price * 0.9;
},
}
apple.calcPrice();
arrow関数
独自のthisキーワードは持たないため、呼び出し元の親スコープがthisとなります。
下記の場合、appleはグローバルオブジェクトで、親がwindowになります。
thisは、windowオブジェクトのpriceプロパティを探そうとするのですが、もちろんwindowオブジェクトにpriceプロパティはないので意図する値は返ってきません。
const apple = {
price: 150,
calcPrice: () => console.log(this.price * 0.9),
}
apple.calcPrice();
通常の関数
通常の関数内(function declarationやfunction expression)でのthisキーワードは"undefined"となります。(※strict modeの場合)
注意ポイント
①メソッドでは常に呼び出し元オブジェクトを参照する
下の例にあるように、appleのcalcPriceメソッドをbananaオブジェクトにコピーします。
bananaオブジェクトでは、calcPriceメソッドにあるthisキーワードはappleオブジェクトのpriceか、bananaオブジェクトのpriceのどちらを参照すると思いますか??
答えはbananaオブジェクトです。常に呼び出し元オブジェクトを参照するからです。
//appleオブジェクト
const apple = {
price: 150,
calcPrice: function() {
return this.price * 0.9;
},
}
console.log(apple.calcPrice()); //result -> 135
//bananaオブジェクト
let banana = {
price: 200,
}
banana.calcPrice = apple.calcPrice; // apple.calcPriceメソッドをbananaオブジェクトにコピー
console.log(banana.calcPrice()); //result -> 180
②メソッドの中で書かれていても関数ならundefinedとなる
下の例は、メソッドの中に書かれていようが、関数なのでthisはundefinedとなり、下記は正しく動きません。
const apple = {
price: 150,
calcPrice: function() { //calcPriceメソッド
console.log(1000 - this.price);
const log = function() { //log関数
console.log(this.price);
}
log(); //log関数呼び出し
},
}
apple.calcPrice();
ただこちらは回避する方法が二つあります。
解決法①:thisを別の変数に代入しておく。
const apple = {
price: 150,
calcPrice: function() {
console.log(1000 - this.price);
const self = this; //thisをselfに代入する(appleオブジェクトがselfとなる)
const log = function() {
console.log(self.price); //apple.priceと同じ意味になる
}
log();
},
}
apple.calcPrice();
メソッドの中で、thisを別の変数に代入しておけば解決できます。
変数には慣習的にselfや_thisやthatが使われるようですね。
解決法②:arrow関数を使用する
const apple = {
price: 150,
calcPrice: function() {
console.log(1000 - this.price);
const log = () => {
console.log(this.price);
}
log();
},
}
apple.calcPrice();
先程も見たようにarrow関数を使用すると、呼び出し元の親スコープがthisとなります。
log()の呼び出し元=calcPriceメソッドで、メソッドはappleオブジェクトを参照するため、thisはapple.priceとなります。
以上です。