Skip to content

5.4 this

クラスのメソッド内で自分自身(インスタンス)を参照するために使われる this ですが、その中身が何になるかは「宣言された場所」ではなく「関数の呼び出され方」によって決まるという特殊な性質を持っています。

5.4.1 関数の中のthisは呼び出し方によって決まる

Section titled “5.4.1 関数の中のthisは呼び出し方によって決まる”

通常の関数(function やメソッド記法)における this は、関数がどう呼び出されたかに依存します。

  • メソッド呼び出し: uhyo.isAdult() のように オブジェクト.メソッド() の形で呼び出した場合、this はドットの左側のオブジェクト(uhyo)になります。
  • ただの関数呼び出し: メソッドを変数に代入してから isAdult() のように単独で呼び出すと、thisundefined となります(strictモード時)。この状態で this.age などにアクセスしようとするとランタイムエラーが発生します。

アロー関数は、通常の関数とは異なり「自分自身の this を持たない」という特殊な性質があります。

  • 外側のthisを受け継ぐ: アロー関数内の this は、そのアロー関数が定義された外側のスコープの this と同じになります。
  • コールバック関数に最適: array.filter(u => u.age > this.age) のようにメソッド内で配列処理を行う際、アロー関数を使えば意図した通りにインスタンスの this を参照できます。昔のJavaScriptで必要だった const _this = this; のような退避テクニックは不要になりました。

関数オブジェクトには、呼び出し時の this を明示的に指定するためのメタプログラミング的なメソッドが用意されています。

  • applycall: どちらも this を指定して関数を実行します。func.apply(obj, [arg1, arg2]) のように引数を配列で渡すか、func.call(obj, arg1, arg2) のように展開して渡すかの違いです。
  • bind: func.bind(obj) とすることで、this が常に obj に固定された新しい関数オブジェクトを作成して返します。
  • 注意点: アロー関数で作られた関数に対しては、これらのメソッドを使って後から this を書き換えることはできません。

関数の外で this が使われた場合の挙動も環境や文脈によって定まっています。

  • プロパティ宣言の初期化式: クラス内で bar = this.foo + 100 のように書いた場合の this は、コンストラクタ内と同様に「これから作られるインスタンス」を指します。
  • 静的プロパティ・静的ブロック: static な文脈で使われた this は、インスタンスではなく「クラスオブジェクトそのもの(例:User クラス)」を指します。
  • トップレベル: どの関数にも属さない一番外側の場所では undefined となります(strictモード時)。

コラム24 組み込みオブジェクトとクラス――配列の継承を例に――

Section titled “コラム24 組み込みオブジェクトとクラス――配列の継承を例に――”

ArrayMapDate などの組み込みオブジェクトは、実質的にクラスと同じように振る舞い、new を用いてインスタンス化できます。

  • Array クラス: 配列は Array<T> クラスのインスタンスです。new Array<number>() のように作成することも可能ですが、new Array(10) とすると「長さ10の中身がない配列」ができる罠があるため、通常は配列リテラル [] が推奨されます。
  • 継承: class RepeatArray<T> extends Array<T> のように、組み込みオブジェクトを継承して独自のメソッドを追加したクラスを作ることも可能です。