JavaScriptのthis
-
2024年6月18日
はじめに
皆様こんにちは。サーバーエンジニアのGZRと申します。
JavaScriptが世の中を席巻している時代において、皆さんはJavaScriptとは仲が良いでしょうか。今回は、仲良くなるのが難しいと感じる「this」についてお話させていただこうかと思います。
why ‘this’
なぜ「this」という仕組みが実装されているのか、例を見ていきましょう。
例1-1:
// 1-1 <script> const obj = { oops: 1, method: function () { console.log(oops) } }; obj.method() // Uncaught ReferenceError: oops is not defined </script>
例「1-1」では、methodが実行される時に、まず関数スコープから「oops」を探します。
みつからないため、外側のスコープに探しに行くことになります。しかし「obj = { … }」が囲んでいる部分はscopeではありません。
その結果、グローバルスコープ(window)にたどり着き、グローバルスコープにでも「oops」が存在しないため、エラーとなりました。
例1-2:
<script> let oops = 3 // obj.methodに保存されているのは関数のアドレスに過ぎないため、 ここに定義し参照しても同じ function fn() { console.log(oops) } const obj = { oops: 1, method: fn }; const obj2 = { oops: 2, method: fn }; obj.method() // 出力:3 obj2.method() // 出力:3 </script>
例「1-2」のように、グローバルスコープに「oop」を定義すると、両方とも「3」が出力されます。では、どうすればfn関数実行時の「指向対象」を固定して各オブジェクトにある「oops」の値を出力できますでしょうか。
ここで「this」が登場します。
例1-3:
<script> let oops = 3 function fn() { console.log(this.oops) } const obj = { oops: 1, method: fn }; const obj2 = { oops: 2, method: fn }; obj.method() // 出力:1 obj2.method() // 出力:2 </script>
thisを利用すれば、呼び出し元のオブジェクトへの参照を保持することができるため、「3」ではなく、「1」、「2」がちゃんと出力されますね。
補足:thisの指向について
<script>
const obj = {
oops: 1,
method: function () {
console.log(this.oops)
}
};
obj.method() // 出力:1
var oops = 3
let fn = obj.method
fn() // 出力:3
</script>
オブジェクトにあるメソッドを別のオブジェクトの属性(この例ではwindowオブジェクトのfn)に代入すると、thisの指向対象も自動的にwindowオブジェクトへと変わります。
それによって、fn()の出力結果はwindowオブジェクトのoopsの値「3」となります。
ちなみに、別のJSトラップになりますが、「var oops = 3」の代わりに、「let oops = 3」または「const oops = 3」にすると出力結果は「undefined」になります。(var、let、constの違い)
クイズ
//クイズ <script> var oops = 3 const obj = { oops: 1, method: function () { console.log(this.oops) } }; obj.method(); // 出力:1 (obj.method = obj.method)() // 出力:3 </script>
自分のメソッドにそのメソッドをそのまま再代入しているだけなのに、なぜ出力結果はwindowの「oops」値に変わったでしょうか。
最後にひとこと
—「身構える時には、バグは来ないものだ」
最後までお読みいただきありがとうございます、次回:thisの参照先変更して関数を呼び出す方法を紹介いたします。