今回は「クラス」についてご紹介させて頂きます。
実は、JavaScriptでは本来「クラス」という概念は存在していませんでした。
他の言語では「クラス」があるのに、JavaScriptにないということで、コードによっては非常に読みづらいものになっていました。
そのため、ES2015(ES6)というJavaScriptのアップデートで新たに追加されたものの一つが「クラス」なのです。
JavaScriptにおいて「クラス」とは、動作や状態を定義した構造になっていて、簡単に言うと今まで学習してきた関数やオブジェクトをひとまとめにして使えるようにするものです。
これだけだとよく分からないと思いますので、早速実際の例を見ながら学習していきましょう。
クラスの定義方法
クラス宣言
class MyName { constructor(){ } }
基本的には「class クラス名 {}」で定義します。
構文の中に、「constructor(){}」と記述されていますが、これは「コンストラクタ」のことであり、前回学んだ「コンストラクタ関数」と同じような定義を行っていきます。
すべてのクラス構文には、「コンストラクタ」が自動的に定義されますので、「constructor(){}」を書かなくても空のコンストラクタは定義されています。
なお、「クラス名」の最初の単語は大文字で書くようにしてください。
クラス式
let myName = class { constructor(){} };
どこかで見たことがあるような書き方ですね。
すでに学習した関数式(無名関数)と同じような書き方です。
関数式と同様に、ここではクラス名を書いていません。
コンストラクタを定義する
class MyName { constructor(name,age,address,interests){ this.name = name; this.age = age; this.address = address; this.interests = interests; } }
「constructor」の定義は前回学習した「コンストラクタ関数」とほぼ同じです。
引数を指定して、「this」を使って「class」自身に値を保持させます。
続いてインスタンスを生成していきます。
let person1 = new MyName('太郎', 33 , 'Tokyo', 'サッカー'); person1; MyName {name: '太郎', age: 33, address: 'Tokyo', interests: 'サッカー'} address: "Tokyo" age: 33 interests: "サッカー" name: "太郎" [[Prototype]]: Object
こちらも「コンストラクタ関数」と同じです。
「new演算子」を使用するのを忘れないでください。
これにより、「MyName」の構造をもったオブジェクトを生成して、「person1」に格納しています。
メソッドを定義する
class MyName { constructor(name,age,address,interests){ this.name = name; this.age = age; this.address = address; this.interests = interests; } function(){ alert('私は'+ this.name + 'です。' + '年齢は' + this.age + 'です。' + '住所は' + this.address + 'です。' + '趣味は' + this.interests + 'です。' ); } } let person1 = new MyName('太郎', 33 , 'Tokyo', 'サッカー'); console.log(person1.function());
こちらもほとんど「コンストラクタ関数」と同じです。
なおここで定義されたメソッドはプロトタイプメソッドとして扱われます。
Getter と Setter
Getter
class MyName { constructor(name,age,address,interests){ this.name = name; this.age = age; this.address = address; this.interests = interests; } get personName(){ return this.name; } } let person1 = new MyName('太郎', 33 , 'Tokyo', 'サッカー'); console.log(person1.personName); 太郎
ゲッターメソッドを使用する目的は、「プロパティの参照」です。
「get personName(){}」とget構文を使用して定義します。
ゲッターメソッドの場合は必ず値を返す必要がありますので、「return this.name;」を記述します。
Setter
class MyName { constructor(name,age,address,interests){ this.name = name; this.age = age; this.address = address; this.interests = interests; } set personName(value){ this.name = value; } get personName(){ return this.name; } } let person1 = new MyName('太郎', 33 , 'Tokyo', 'サッカー'); person1.personName = 'ジロウ'; console.log(person1.personName); ジロウ
セッターメソッドを使用する目的は、「プロパティへの代入」です。
set構文を利用して定義します。
引数に値を渡すための「value」を記述します。
nameが変わっているのが確認出来ると思います。
基本的に、「Getter」と「Setter」はペアで使用します。
静的メソッド
class Greeting{ static hello(){ return 'Hello'; } } console.log(Greeting.hello()); Hello
クラスをインスタンス化せずに利用出来るメソッドが、「静的メソッド」になります。
定義の仕方は、メソッドの前に、「static」を付けるだけです。
クラスの継承
extends
class MyName { constructor(name,age){ this.name = name; this.age = age; } } class Person extends MyName{ hello(){ console.log('こんにちは' + this.name + 'さん'); } } let person1 = new Person('太郎',33); person1.hello(); こんにちは太郎さん
クラス構文では「extends」を使って「継承」させることが出来ます。
ここでの「継承」とは元になるクラスの機能を、新しく定義するクラスでも使えるようにすることです。
いわゆる親子関係のようなものだと考えてください。
最初に「MyName」というクラスを定義します。
プロパティには「名前」と「年齢」が定義されています。
次に新しい「Person」というクラスを定義します。
この時、「class Person extends MyName」と記述しています。
「class + 新クラス名(子) + extends + 旧クラス名(親)」
その後は、hello関数を定義していますが、コンソールへの出力時に、MyNameクラスの「this.name」を指定しています。
「let person1」でインスタンスを作成します。
「person1.hello();」の実行結果は、「こんにちは太郎さん」ときちんと「this.name」を取得しています。
つまり、PersonクラスはMyNameクラスを継承していることが分かります。
super
class MyName { constructor(name,age){ this.name = name; this.age = age; } hello(){ console.log('こんにちは' + this.name + 'です。' + '年齢は' + this.age + '歳です。'); } }
MyNameクラスを定義します。
コンストラクタに、名前を年齢のプロパティがあります。
挨拶文を表示する「hello()」メソッドが定義されています。
class Person extends MyName { constructor(name, age, interests){ super(name,age); this.interests = interests; } hello(){ super.hello(); console.log('私は' + this.interests + 'が大好きです。'); } }
MyNameクラスを継承する、Personクラスを作成します。
先程の「extends」の説明のときは、コンストラクタがありませんでしたが、ここでは名前と年齢、趣味の3つの引数を持つコンストラクタを定義しています。
通常、「this.name; this.age;」と書くところを、ここではMyNameクラスのプロパティにアクセスするため、「super(name,age);」と記述しています。
このように、「super()」を使ってプロパティを書くと、継承元のプロパティを引き継ぐことが出来ます。
ここでのように新たなプロパティ「this.interests = interests;」を記述する場合は、「super()」の下に書くようにしてください。
言い方を変えると、「super()」は「constructor」の直下に書くようにしてください。
「super()」を記述する場所によってエラーが起こる場合があります。
let person1 = new MyName('太郎', 33); person1.hello(); こんにちは太郎です。年齢は33歳です。
MyNameクラスにインスタンスを作成して、メソッドを実行すると、挨拶文が返されます。
let person2 = new Person('花子', 30, '水泳'); person2.hello(); こんにちは花子です。年齢は30歳です。 私は水泳が大好きです。
Personクラスにインスタンスを作成して、メソッドを実行すると、MyNameクラスのメソッドを実行しているのが確認出来ます。
クラスの継承で、コンストラクタのない子クラスが引き継ぐ場合は、「extends」だけでも親クラスのメソッドを引続ことが出来ますが、子クラスでコンストラクタを定義すると、「super()」を記述しないと、親クラスのメソッドを引き継ぐことが出来ません。
あとがき
いかがでしたか。
今まで学習してきた、関数とオブジェクトがしっかりと頭に入っている方にとってはそれほど難しくはなかったかもしれません。
すっきりされなかった方は、もう一度、関数とオブジェクトを読み直してから、再びクラスを学習してみてください。
JavaScriptの学習は、HTMLやCSSと違って、なかなか目に見える形がないので、概念の学習に手応えを感じないかもしれませんが、残りもあと僅かです。
ぜひ最後まで頑張って学習を続けていきましょう。
今回も最後までお読み頂きありがとうございました。