5.4 this
クラスのメソッド内で自分自身(インスタンス)を参照するために使われる this ですが、その中身が何になるかは「宣言された場所」ではなく「関数の呼び出され方」によって決まるという特殊な性質を持っています。
5.4.1 関数の中のthisは呼び出し方によって決まる
Section titled “5.4.1 関数の中のthisは呼び出し方によって決まる”通常の関数(function やメソッド記法)における this は、関数がどう呼び出されたかに依存します。
- メソッド呼び出し:
uhyo.isAdult()のようにオブジェクト.メソッド()の形で呼び出した場合、thisはドットの左側のオブジェクト(uhyo)になります。 - ただの関数呼び出し: メソッドを変数に代入してから
isAdult()のように単独で呼び出すと、thisはundefinedとなります(strictモード時)。この状態でthis.ageなどにアクセスしようとするとランタイムエラーが発生します。
5.4.2 アロー関数におけるthis
Section titled “5.4.2 アロー関数におけるthis”アロー関数は、通常の関数とは異なり「自分自身の this を持たない」という特殊な性質があります。
- 外側のthisを受け継ぐ: アロー関数内の
thisは、そのアロー関数が定義された外側のスコープのthisと同じになります。 - コールバック関数に最適:
array.filter(u => u.age > this.age)のようにメソッド内で配列処理を行う際、アロー関数を使えば意図した通りにインスタンスのthisを参照できます。昔のJavaScriptで必要だったconst _this = this;のような退避テクニックは不要になりました。
5.4.3 thisを操作するメソッド
Section titled “5.4.3 thisを操作するメソッド”関数オブジェクトには、呼び出し時の this を明示的に指定するためのメタプログラミング的なメソッドが用意されています。
applyとcall: どちらもthisを指定して関数を実行します。func.apply(obj, [arg1, arg2])のように引数を配列で渡すか、func.call(obj, arg1, arg2)のように展開して渡すかの違いです。bind:func.bind(obj)とすることで、thisが常にobjに固定された新しい関数オブジェクトを作成して返します。- 注意点: アロー関数で作られた関数に対しては、これらのメソッドを使って後から
thisを書き換えることはできません。
5.4.4 関数の中以外のthis
Section titled “5.4.4 関数の中以外のthis”関数の外で this が使われた場合の挙動も環境や文脈によって定まっています。
- プロパティ宣言の初期化式: クラス内で
bar = this.foo + 100のように書いた場合のthisは、コンストラクタ内と同様に「これから作られるインスタンス」を指します。 - 静的プロパティ・静的ブロック:
staticな文脈で使われたthisは、インスタンスではなく「クラスオブジェクトそのもの(例:Userクラス)」を指します。 - トップレベル: どの関数にも属さない一番外側の場所では
undefinedとなります(strictモード時)。
コラム24 組み込みオブジェクトとクラス――配列の継承を例に――
Section titled “コラム24 組み込みオブジェクトとクラス――配列の継承を例に――”Array、Map、Date などの組み込みオブジェクトは、実質的にクラスと同じように振る舞い、new を用いてインスタンス化できます。
Arrayクラス: 配列はArray<T>クラスのインスタンスです。new Array<number>()のように作成することも可能ですが、new Array(10)とすると「長さ10の中身がない配列」ができる罠があるため、通常は配列リテラル[]が推奨されます。- 継承:
class RepeatArray<T> extends Array<T>のように、組み込みオブジェクトを継承して独自のメソッドを追加したクラスを作ることも可能です。