JavaScriptのクラス(class)を理解する
多くのオブジェクト指向プログラミング言語には標準的な機能として【クラス】構文が備わっています。
JavaScriptは長らくクラス構文が存在しませんでしたが、ECMASCript2015(2015年版のJavaScriptの仕様)でクラス構文が追加されました。
今回は、JavaScriptのクラス(class)構文について解説していきます。
追加されたJavaScriptのクラス(class)構文
オブジェクト指向
と呼ばれるプログラミング言語についての概念があります。
オブジェクト指向とはプログラムを現実のモノのように構成する
指向のことです。
このオブジェクト指向の言語として作られたプログラミング言語には、多くの場合クラス
という機能が備わっています。
JavaScriptは、オブジェクト指向のプログラミング言語でありながら、このクラス
機能が長らく実装されていない、珍しい言語でした。
しかし近年、JavaScriptの新しい標準が改訂されたことにより、JavaScriptにもクラス
機能が実装されました。
クラス(class)とは
多くのオブジェクト指向プログラミング言語に備わるクラス(class)
という概念について紹介します。
クラス(class)とは、端的にいえばモノの設計書
です。
先ほどオブジェクト指向とは、プログラミングを現実のモノのように構成する
ものだと解説しましたが、クラスとはこのモノのように構造する
際の、モノ
そのものの設計書
にあたります。
言葉としては、以下のような意味の対応表になります。
- オブジェクト = モノ
- クラス = モノ(オブジェクト)の設計書
クラス
はモノ(オブジェクト)の設計書
であるため、多くのプログラミング言語においてモノ(オブジェクト)
を作成する際に必要なものとして定義されることが多いです。
なお、JavaScriptやHTMLのみしか触れたことのない方は、ここで解説するclass
がHTMLのclass属性
とはまったく異なるものであることに気を付けてください。
JavaScriptを用いてHTMLのclass属性の取得や変更、追加や削除などを行うことがありますが、そういったHTMLを操作する際に登場するclass
という言葉は、プログラミング言語の構文としてのclass
とは関係のない概念です。
JavaScriptのクラス(class)の特徴
JavaScriptにおいてもクラス
がオブジェクト指向におけるモノ(オブジェクト)の設計書
であることについては間違いありません。
多くのプログラミング言語と同様のコンストラクタ
や継承
といった概念を備えています。
しかし、特殊なのはその書き方です。クラス変数はコンストラクタの中でのみ記載できる
ことや、クラス直下にはfunction(メソッド、関数)のみしか配置できないこと
当、慣れないと少々書くのが困難なルールがいくつか存在しています。
JavaScriptのクラス(class)の作り方
まず注意すべきことがあります。
JavaScriptにおけるclassは、ECMAScript2015 という近年の新しいJavaScriptの標準として組み込まれた構文です。
そのためInternetExplolerなど一部のブラウザやブラウザのバージョンによっては、この新しい標準への対応が行われおらず、ここで紹介するコードが機能しない可能性があります。
しかし新しい標準のJavaScriptの機能として組み込まれており、徐々に未対応のブラウザが少なくなっているため、現在JavaScriptを学習している方は覚えておいて損はないでしょう。
さて、以上のことを念頭に踏まえた上で解説を進めていきます。
JavaScriptにおける関数の定義
には、2つの方法がありました。
ひとつが関数宣言
。
もうひとつが関数式
です。
これと同様に、JavaScriptのクラスの定義
にも2つの方法があります。クラス宣言
とクラス式
です。
クラス宣言
クラス宣言
によるクラスの定義は以下のように行います。
class Fooclass {
// ...クラスの内容をここで定義する
}
関数宣言
時に発生するホイスティング(巻き上げ)
は、クラス宣言
時には発生しません。
そのため、クラスを使用したい場合は必ずクラスを使用する前に、クラス宣言を行う
ことが必要となります。
クラス式
クラス式
によるクラスの定義は以下のように行います。
const fooclass = class {
// ...クラスの内容をここで定義する
}
クラス式
の場合、その名の通り、式としてクラスを定義
することができます。
変数に代入するclass式は無名クラス
でも名前つきクラス
でも可能です。
コンストラクタ(constructor)とメソッド定義
クラス宣言
やクラス式
でクラスを定義する際、そのクラスの中身がどのようなものなのかについて、JavaScriptでは主にコンストラクタ(constructor)
とメソッド
で定義していきます。
コンストラクタは次のように書きます。
const fooclass = class {
constructor(x, y) { /* コンストラクタ */
this.x = x
this.y = y
}
}
constructor()という名前のメソッドがコンストラクタ
と呼ばれるものです。
コンストラクタは定義したクラスからオブジェクトを生成し、初期化する際に実行される特殊な初期化用メソッド
です。
constructor()内でthis.x
にconstructor()の第一引数x
を代入していますが、これは自身のプロパティxに指定された引数の値を設定する
という意味になります。
これにより、オブジェクトが自らのプロパティとその値を設定できるようになります。
また、コンストラクタとは別に通常のメソッド
もクラスの内容として定義することが可能です。
コンストラクタの他にメソッドも定義する場合、以下のようなコードになります。
const fooclass = class {
constructor(x, y) { /* コンストラクタ */
this.x = x
this.y = y
}
calc() { /* メソッド */
return this.x + this.y /* x と y を足した値を返却する */
}
}
上記コードのcalc()がクラス内でのメソッド定義
になります。
ここでは、fooclassクラスのプロパティ x と y を足した値を返すメソッドとして定義しています。
このようにクラス内でコンストラクタとメソッドを定義することで、クラスからオブジェクトを作成した際に、定義したコンストラクタのプロパティと、メソッドを使用することができるようになります。
JavaScriptのクラス(class)の使い方
クラスはクラス宣言
やクラス式
によって定義しただけでは役に立ちません。
クラスはオブジェクト指向におけるモノの設計書
であり、役割は設計したモノを生成すること
です。
つまり基本的には、オブジェクトを作成してはじめて、クラスという概念が役に立つといえるでしょう。
(1)オブジェクトの作成(new)
クラスから、クラスのインスタンスであるオブジェクト
を作成するためにはnew
演算子を用いる必要があります。
new演算子を用いたオブジェクトの作成は、次のように行います。
var foo1 = new fooclass(10, 20)
これでfooclassのインスタンス(オブジェクト)
が作成され、変数foo1に代入されました。new演算子 + クラス + 括弧
でオブジェクトが作成されるのです。
この際に登場する括弧
は、クラス定義の際に登場したコンストラクタ(constructor)
に渡される引数を示します。
(2)プロパティの取得と設定
クラスのプロパティは以下のように呼び出すことが可能です
var hooclass = class {
constructor(z) {
this.z = z
}
get getZ() {
/* get構文 */
return this.z
}
}
var hoo = new hooclass(20)
var val = hoo.getZ
console.log(val) /* 20が出力される */
クラス定義の中にget
という構文があります。
このget
構文を用いることで、オブジェクト作成後、get構文で指定したメソッドの返却値を取得できます。
また値を取得するget構文に対し、値を設定するset構文というものが存在します。
var hooclass = class {
constructor(z) {
this.z = z
}
get getZ() {
return this.z
}
set setZ(z) {
/* set構文 */
this.z = z
}
}
var hoo = new hooclass(20)
hoo.setZ = 100 /* プロパティに値を設定する */
var val = hoo.getZ
console.log(val) /* 100が出力される */
set構文で指定された上記コード中の valueOfZ() メソッドを使用すると、インスタンス作成後に、そのインスタンスのプロパティに値を設定することができます。
ここでははじめ、コンストラクタによりプロパティ z を 20 で初期化したインスタンスが、set構文で指定したメソッド valueOfZ に 100 を渡すことで、プロパティ z を 100 に再設定しています。
(3)継承
オブジェクト指向における代表的な概念のひとつに継承があります。
継承とは、クラス間に親子関係を作り出し、親のクラスが保有するメソッドやプロパティを使用できるようにするものです。
継承を行うには extends を利用します。
var hooclass = class {
constructor(z) {
this.z = z
}
get getZ() {
return this.z
}
set setZ(z) {
/* set構文 */
this.z = z
}
}
/* hooclassの継承 */
var taaclass = class extends hooclass {
constructor(z, num) {
super(z) /* 親クラスのコンストラクタ */
this.num = num
}
calc() {
return this.z * this.num
}
}
var taa = new taaclass(20, 3)
taa.setZ = 100 /* 親クラスのメソッドでプロパティに値を設定する */
console.log(taa.calc()) /* 300が出力される */
クラス作成時、上記コードのように extends + “継承したいクラス名” で親クラスを指定することが出来ます。
継承する親クラスのプロパティを初期化するために、constructor には親クラスのコンストラクタを示す super() の引数に、初期化したい値を指定する必要があります。
(4)静的メソッド
クラスのインスタンスではなく、クラスそのものから呼び出しを行う静的メソッドというものが存在します。
var hooclass = class {
static writeDescription() {
/* staticをつけることで静的メソッドを定義できる */
return 'これが静的メソッドです。'
}
}
console.log(hooclass.writeDescription()) // 静的メソッド実行
上記コード中のwriteDescription()メソッドの定義箇所を見てみましょう。
メソッド名の前に static とあります。
これは、ここで定義するメソッドが静的メソッドであることを示します。
静的メソッドはクラスのインスタンスではなく、クラスそのものから呼び出しを行うため、クラス名.静的メソッド名() のみで実行することができます。
まとめ
JavaScriptで新しく追加されたclass構文を用いることで、オブジェクト指向としてさらに可読性の高いコードを書くことができるようになります。
クラス式・クラス宣言によるクラス定義と、new演算子によるクラスのインスタンス(オブジェクト)の作成、親クラスの継承や静的メソッドをうまく活用して、より高い可読性のコードを実装していきましょう。