クラス class
オブジェクト指向プログラミング言語においてクラス
とはオブジェクトを生成するための設計図みたいなものです。クラスを元にそっくりなオブジェクトデータが生成されます。
クラスから生成されるのはインスタンス
といいますが、JavaScript ではオブジェクトという記載が多いです。
すべてをオブジェクトで解説することによる混乱を防ぐためにクラスから生成されるのはインスタンスと解説します。
ここでは主にクラス( class )について解説します。オブジェクトについてはオブジェクト
または連想配列型( Object )
ページを参照してください。
クラスについて
JavaScript におけるクラス定義とそのインスタンスの生成についてです。
オブジェクトは、それ自身固有のデータ群と関数群を持つデータという抽象(イメージ)です。
オブジェクト型のデータ構成を定義することをクラスの定義といい、クラスからオブジェクト型のデータを宣言(メモリを確保)することを、インスタンスを生成または作成するといいます。
上記は、オブジェクト型(連想配列型)の変数を1つだけ宣言する例です。ここではクラス( class )を使用して同じようなデータ構成のオブジェクトデータを生成する方法を解説します。
クラス定義について
クラス定義では以下のようにインスタンスのプロパティ( property )とメソッド( method )を定義します。プロパティはインスタンスのデータのことで、メソッドは関数です。
上記の例には、コンストラクター( constructor )があります。これはクラスを使ってインスタンスを生成するときに必ず呼び出される部分です。
constructor() はインスタンス生成時に呼び出されるためにプロパティの定義とプロパティの初期化に利用することができます。
インスタンスの生成
上記のクラス定義からインスタンスを生成するには以下のようにします。
プログラム上では Object 型のリテラルを代入する変数を宣言することで、インスタンスが生成、作成されます。 コンピュータ上では、変数宣言によってメモリが必要なだけ確保された状態です。
変数宣言には、var、let、const ステートメントがあります。変数として宣言するには、letを。同じ変数名が出現しないようにするには const を使います。var は間違いが起こりやすいので使うのは控えたほうがよいようです。
プロパティ( property)とメソッド(method)の使用
以下のようにインスタンスのプロパティ( property)やメソッド(method)を使用することができます。
JavaScript と HTML
JavaScript はブラウザで稼働するスクリプト言語です。HTML で使用することを前提にしています。
HTML のタグエレメントも DOM という機能を通してオブジェクトとして扱います。
HTML は、独自にクラス定義から行わなくても、タグエレメント自体をオブジェクトとして利用すればよいケースが多々あります。継承を使うことや、複数のタグエレメントのハンドラーをもつ任意のクラス定義もあるでしょう。さらに、関数に関しても便利な関数が用意されている場合がありますので、それを利用するとよいでしょう。(DOMやビルトインオブジェクトなど)
JavaScript では HTML タグエレメントをオブジェクト(DOM)として扱います。DOM について詳しくはDOM
ページを参照してください。
プロパティとメソッド
クラスにはプロパティとメソッドを定義することができます。
プロパティはオブジェクトを表す変数で、メソッドは主に変数を操作するための関数です。
以下の例はクラス宣言をして、そのクラスを元にオブジェクトの配列を作成しています。
クラスから生成されたオブジェクトで、name プロパティや get_Name() メソッドが機能します。
プロパティについて
プロパティは変数名(識別子)とその値の組み合わせです。キーと値と言ったりもします。プロパティの順番は決まっていません。
プロパティは以下のようにオブジェクトの後に.
または[ ]
を使って指定します。
このことは連想配列に準じています。
プロパティにはプロパティ自体を操作するための Object.defineProperty()、Object.getOwnPropertyDescriptor() といったメソッドがあります。
ディスクリプタの操作によって、プロパティの変更、列挙型、削除といった既定の性質を変更することができます。
プロトタイプ
プロトタイプはクラスを宣言するとクラス以下に自動で作成されます。
クラスを元にインスタンスを生成するとそのプロパティやメソッドがコピーされ、インスタンスごとに独立しているようにみえます。
実際にはクラスのプロトタイプを経由しながら各インスタンスのプロパティの参照やメソッドの実行が行われます。
そのために、this が参照しているインスタンスが想定と違うといった現象が起きます。
クラスやインスタンスは元になるクラスを継承しています。その継承はプロトタイプによって繋がっています。このことをプロトタイプチェーン
といいます。
プロトタイプの存在は意識する必要がないですが、エラーが起きたい場合にその解決の糸口になるかもしれません。
static(静的)メソッド
JavaScript で静的メソッドが利用できるようになっています。
静的メソッドはインスタンスの生成なしに利用することができるメソッドです。
例えば、以下のような Object クラスの keys() メソッドが静的メソッドです。
keys() メソッドは Object クラスに定義されていますが、クラス名に続いて .keys() で呼び出すことができます。
静的メソッドはstatic
ステートメントで定義されたメソッドです。
上記の例のように static に続いて定義されたメソッドが静的メソッドして機能します。
static はこのクラス内だけで機能するという意味です。このような静的メソッドの定義は、インスタンスから呼び出すことができないという特性があります。
Example
例えば、クラスによって複数のインスタンスを作成するのですが ID といったインスタンスごとの一意のデータが必要になることがあります。
そのような場合に ID のためのシーケンスをクラスに記憶させておいて静的メソッドで ID を作成することができます。
クラス自体に変数を宣言してデータを記憶させておくことができます。
そして、クラス定義の外でシーケンスを初期化(例えば、Class_City.sequence_id = 0;
)をする必要がありますが、クラスがデータを記憶しています。
get ステートメントと set ステートメント
JavaScript にはあらかじめ、プロパティ値の取得と設定ができるメソッドとして定義できる get と set という特殊なステートメントが用意されています。これらはアクセッサプロパティと呼ばれます。
get ステートメントはプロパティ値を取得し、 set ステートメントは値を設定します。これらのステートメントはメソッドの前に付けることで、そのメソッドは引数を指定しなくてもデータの取得と設定を専用に行うことができます。
get と set は上記のように実際のプロパティを隠蔽することができます。
JavaScript ではプロパティを直接変更することができるという欠点をもっています。これを補うために、get や set を使用してメソッドをプロパティのように扱い、実際のプロパティ名を隠蔽します。
上記の例のようにプロパティには
のような別名にし、get や set では_population
という想像しやすい名称にします。
population
このことでユーザーは
というように実際の変数名をユーザーから隠蔽することができます。cities[0].population
get のみを定義し set を定義しないこともできます。そのことで読み込むことができても書き込むことができないといった使い方ができます。
上記のように get のみを定義することで値を取得するのみで代入を防ぐことができます。
アクセッサプロパティは特殊で、上記の例のように get、 set は関数として定義をするのですが、オブジェクトのプロパティを扱うObject 名.Property 名
という文で値の取得と代入ができます。
クラスの継承(extends)
JavaScriptにおいてクラスの継承は、extendsステートメントを使います。
継承とは、あるクラスを元に機能を追加したクラスを定義する方法です。
上記の例では、Example_Class では都市名とその人口を記憶するためのものですが、そのクラスを継承した Extends_Class によって.. の人口は .. 万人です。
というコメントを出力することができます。
このように継承によってより充実したクラスや元のクラスを変更しないで新たな似たクラスを定義することができます。
super (コンストラクターの継承)
extends ステートメントでクラスが継承できるのですが、コンストラクターは super ステートメントを使って継承しないと上書きされてしまいます。
そのために継承クラスで super を利用しないでコンストラクターを定義してしまうと、親クラスのパラメーターが参照できずに method などが使えない場合が発生します。
super() は継承元の親クラスのコンストラクターを呼び出すものです。そのため、引数は親のコンストラクターの引数に合わせます。
インターフェイス、ミックスイン
クラスの継承は1対1の関係であることが好ましいです。多重継承はプロパティやメソッドが多重に衝突する危険性を含みます。そのために1つの親からは1つの子しか存在しないということの方が好ましいのです。
実際には、1つの親を元に複数のクラスを定義する、または複数の親クラスから継承するしたほうが都合がいい場合があります。それを可能にするのがインターフェイス、ミックスインという機能です。
しかしながら、JavaScript ではインターフェイスという構文はありません。クラスの継承を利用します。
インターフェイス
インターフェイスとは抽象クラスとも呼ばれ、クラスによって継承されることを前提としたクラスまたインスタンスの生成の元になるクラスのことです。
JavaScript におけるインターフェイスとは、1つの親クラスから複数の子クラスが継承する方法です。
以下の例は地域ごとの名称と人口を記録するクラスです。このクラスを元に都道府県ごとの名称と人口を記憶するクラス、市町村ごとの名称と人口を記憶するクラスを定義します。
JavaScript では1対1というクラス継承でなければないことを規制していません。そのために、このような1つのクラスを複数のクラスで継承することができます。
しかし、複数のクラスを1つのクラスで継承することは許していません。これを行うにはミックスインを使用します。
ミックスイン
ミックスインという複数のクラスを1つのクラスで継承する機能があります。
ミックスインはクラスではなく関数を利用した複数のクラスを利用できるようにしたものです。
以下は地域名とその人口を記憶するクラスを分けています。人口クラスでは男性と女性を分けて記憶するようにしています。