JavaScriptのthisとは
ふと
JavaScript使ってきてるわりにthisのコンテキストが変わることについて、あんまり理解できてないなーと思ったのでMDN読みながらまとめる
thisとは?
JavaScriptでは式の1つで、関数の実行コンテキストを参照するものである
だが、呼び出し方やアロー関数などでもコンテキストが変わるのでややこしくなっている
use strictとそれ以外でまず異なる
- use strict (厳格)モード
- どのような値でも取り得る
- 非厳格モード
- 実行コンテキスト(グローバル、関数、eval)のプロパティで常にオブジェクトへの参照である
グローバルコンテキストの場合
グローバルコンテキスト(トップレベル)ではthisはグローバルオブジェクトを参照する
console.log(this === window); // true
関数コンテキスト
関数内のthisは関数の呼び出され方と厳格モードの有無によって異なる
非厳格モード
呼び出し時にthisの値が設定されない場合規定のグローバルオブジェクトとなる
function func() { return this; } func() === window; // true
厳格モード
呼び出し時にthisの値が設定されていない、つまり関数がオブジェクトに属していない形で呼び出されるとundefinedのままになる
function func2() { 'use strict'; return this; } console.log(func2() === window); // false console.log(func2() === undefined); // true
関数の呼び出し時にthisの値を特定の値に設定したい場合にはcallやapplyを使用して呼び出す
function func3() { 'use strict'; return this; } console.log(func3.call(window) === window); // true console.log(func3.apply(window) === window); // true
また、bindで永続的に設定した関数を生成できる
const newFunc = func3.bind(window); console.log(newFunc() === window); // true
Arrow Functionの場合
Arrow Functionの場合のthisは実行時ではなく関数の定義時に決まる
そのthisは自身の外側のスコープに定義されたもっとも近い関数のthisの値を指す
注意点としてArrow Functionはcall, apply, bindでthisを設定することはできない
const arrowFn = () => { // この時外側には関数は存在しないためトップレベルのthis、つまりwindowを指す return this; }; console.log(arrowFn() === window); // true console.log(arrowFn.call({ a: 1 })); // Window {...}
クラスコンテキスト
基本クラスの場合thisはそのクラスを指す また、クラス内の非staticなメソッドはthisのプロトタイプに追加される
class Foo { constructor() { console.log(this); // Foo {} const proto = Object.getPrototypeOf(this); console.log(Object.getOwnPropertyNames(proto)); // ['constructor', 'bar'] } bar() {} static hoge() {} } new Foo();
子孫クラス
継承先の子孫クラスではthisバインディングはなく、super()
を呼び出すとコンストラクタ内にthisバインディングが作成される
このthisはsuperを呼び出したクラス自身を指す
class Base { base() {} } class Child extends Base { constructor() { super(); console.log(this); // Child } } new Child();
オブジェクトのメソッドの場合
オブジェクトのメソッドとして呼び出されるときはthisはメソッドの所属オブジェクトになる
const obj = { count: 10, currentCount: function() { return this.count; } }; console.log(obj.currentCount()); // 10
まとめ
- 基本的にはthisは呼び出し時の所属オブジェクトを指す
- Arrow Functionのthisは呼び出し時ではなく定義時の外側のスコープに定義されたもっとも近い関数のthisを指す
- 関数コンテキストでは厳格モードと非厳格でthisが異なる
JavaScript Primerにもコールバックなどさらに詳しい情報が載っているのでこちらも読んでみようと思います jsprimer.net