最近JavaScriptを勉強し始めた中でthisの使い方がイマイチぴんと来ていないので、今回は、
function(){・・・}(通常関数)()=>{・・・}(アロー関数)
のthisの使い方の違いについてまとめます。
何が違うのか?
私自身、調べる前は「thisの範囲が違うらしい」ということくらいしか分かっていませんでした。
違いを一言で言うと、
- 通常関数の
thisは、functionを呼んだ時の.の前についているオブジェクト - アロー関数の
thisは、関数の外のthis
を指してます。
通常関数を先に説明をします。
通常関数のthis
function test() {
console.log(this)
}
var obj = {}
obj.test = test
obj.test() // => {test: ƒ}
thisはfunctionを呼んだ時の.の前についているobjオブジェクトとなります。
function test() {
console.log(this)
}
test() // => Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
オブジェクトを指定しない場合は、グローバルオブジェクトになります (non-strict モード時)。 strict モードでは undefined になります。
とまあ、**通常関数の場合は関数の呼び出し方に応じてthisの中身が変わります。**下の記事に呼び出し方による違いが書いてあります。
JavaScript の this を理解する多分一番分かりやすい説明 - Qiita
記事は非常に分かりやすく書いてあります。が、実行の仕方によってthisが変わってしまい、分かりにくくないですか? 私は読んでいて嫌になってきました。
その複雑さを改善したのがアロー関数のようです。
アロー関数のthis
アロー関数のthisは、**関数の外側のthis**に固定されます。
const test = () => {
return this
}
// 関数の外側のthis
const lexicalThis = this
// 関数定義したタイミングで、関数の外側のthisを参照する
console.log(test() === lexicalThis) //=> true
// メソッドとして実行しても、thisはメソッドが属するオブジェクトを指さない
const obj = { method: test }
console.log(obj.method() === obj) //=> false
console.log(obj.method() === lexicalThis) //=> true
先ほどの通常関数のobj.test()はthis=objとして扱っていたのに対して、アロー関数のobj.test()はthis=lexicalThis(関数の外側のthis)として扱っていることが分かります。
アロー関数のthisは、.前のオブジェクトは指さず、必ず関数の外側のthisを指します。
また、強制的にあるオブジェクトと結びつけるbind等も無視するようです。通常関数では有効です。
function test() {
console.log(this)
}
var obj = { name: "obj" }
var check = test.bind(obj)
check() // => {name: "obj"}
まとめ
通常関数は、さまざまな参照の仕方があるため汎用性があるが、thisの対象が実行の仕方によって変動してしまう。
一方、アロー関数は、参照するオブジェクトに制約があるものの、オブジェクトが決まっているため分かりやすい。
使用上の注意としては、
- アロー関数を使うときは、間違ってオブジェクトのメソッドとして使わないようにする。
- 通常関数を使うときは、
thisが使い方によって変わることに気を付ける。
以上の2点でしょうか。
アロー関数で書くと格好よく書けるなー、としか思っていませんでした。
思った以上に様々な制約があり、他の違いもしっかり知っておく必要があると感じました。
最後に
通常関数とアロー関数の違いはthisの使い方だけではありません。
その他の違いについてはこちらをご覧ください。
JavaScript: 通常の関数とアロー関数の違いは「書き方だけ」ではない。異なる性質が10個ほどある。 - Qiita
初投稿で拙い文章となってしまいましたが、最後までお読みいただきありがとうございました。
何か誤り等ありましたらご指摘ください。