JavaScript – クラス

クラスの構築

コンストラクタ

JavaScriptではクラス定義はなく、コンストラクタを関数で定義する。

  • thisはこの関数が含まれるオブジェクト(のインスタンス)を指す
  • newによって新しいオブジェクトの無名インスタンスが生成される
  • 代入演算子(=)によって、変数が上記のインスタンスを参照する
  • その結果、thisは定義されたインスタンスを指す

コンストラクタで定義されていないプロパティでも、インスタンスごとに後から追加可能だが、これは可読性やクラスとしての一貫性を損なう。

インスタンスの識別

同じクラスのインスタンスへの参照が同一か異なるかを比較することができる。

この比較はthisを用いても可能。

メソッド

非効率的な方法

コンストラクタの中で、プロパティと同じようにthis.[関数名]と無名関数定義によってプロパティを定義可能。

ただし、thisで指定された対象はインスタンスごとに生成・保持されるため、上記コードではインスタンスの数分のメソッドが生成されてしまう。

prototypeによる方法

JavaScriptにおける全てのオブジェクトはObjectに由来する。すべてのオブジェクトはObject.prototypeからメソッドとプロパティを継承しているが、それらは上書きすることが可能。

インスタンスでメソッドを実行しようとした時にそのメソッドが存在しない場合、そのクラスのprototypeにメソッドを探しに行く。 新たに定義したクラスのprototypeプロパティに関数を定義しておくことで、全てのインスタンスが共通のprototype下のメソッドを利用することになる。

prototypeにメソッドを定義する方法の一つは、メソッド単位でクラスのprototypeに登録する方法と、オブジェクトリテラルでまとめて定義する方法がある。

メソッド単位で定義する方法

メソッドごとにクラスのprotottypeに一つずつ記述していく方法。

オブジェクトリテラルでまとめて定義する方法

クラスの初期設定時に連想配列で定義する。

この方法は、新規にメソッドを定義する場合に一回のみ使用するもので、後から同じ方法でメソッドを追加しようとしした場合、最初の定義内容がすべてオーバーライドされる。

ただ、メソッド定義を敢えてダイナミックに変更するのでなければ、この方法はメソッドの定義のあり方として明快ともいえる。

メソッド定義の注意点

クラスの生成はコンクトラクタの前後を問わないが、メソッドを実行する段階では、prototypeへのメソッドの登録が実行済みでなければならない(記述位置の前後関係ではなく、関数呼び出しも含めた実体上の実行順序)。

C++やJavaなどコンパイラが全体の宣言・定義をパースする場合は問題ないが、インタプリタ系のJavaScriptは、定義=宣言と実行の順序については厳しい。

継承

子クラスのprototypeに親クラスを登録することで継承でき、親クラスのプロパティ、メソッドも利用可能となる。

これは厳密な意味でのクラスの継承というよりは、そのような挙動をするためのprototypeチェーンに組み込んだというところ。

注意点

子クラスのメソッドの定義は必ず親クラスの継承の後で行うこと。継承の際にprototypeの内容が上書きされてしまうため、継承の前にメソッド定義すると子クラスのメソッドが参照されなくなってしまう(下記の例では、”instance.setAge is not a function”とエラーになる)。

子クラスのメソッド定義でオブジェクトリテラルを使ってはいけない。継承の後にこれを行うと、親クラスのメソッドがすべて上書きされてしまう。

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です