最近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
初投稿で拙い文章となってしまいましたが、最後までお読みいただきありがとうございました。
何か誤り等ありましたらご指摘ください。