#概要
この記事では、JavaScriptのクラスについて、超基本的な知識をメモ的にまとめています。
自分用の備忘録なのであしからず。
今回は、FCバルセロナの選手を紹介するプログラムを、クラスを用いて書いてみます。
#目次
#クラスとは
クラスとは特別な関数のことで、オブジェクトを効率良く作成するための設計図です。
JavaScriptは、オブジェクト指向の言語です。
オブジェクト指向とは、プログラムを現実のモノのように構成する指向のことです。
このようにオブジェクトをモノとして考えたとき、そのモノの設計図となるのがクラスです。
Webサービスなどでは、大量のオブジェクトを用いてデータを扱っています。
例えば、ログインが必要なサービスでは、ユーザーに関するデータをオブジェクトとして用いていることが多いです。
このように大量のデータを毎回ゼロから作成するのは大変なので、クラスを用いることで効率よくオブジェクトを作成しています。
##クラスの定義
クラスを宣言する構文は以下に示す通りです。
class クラス名 {
//コンストラクタやメソッドなどをここで定義
}
class クラス名
と書いた後、{ }
の中にコンストラクタやメソッドを定義していきます。
コンストラクタやメソッドについては後ほどまとめていきます。
では、空のクラスを用意してみましょう。
class Barcelona {
}
これで「Barcelona」クラスが用意できました。
##インスタンスの生成
設計図となるクラスを用意できたら、その設計図からオブジェクトを生成します。
クラスからオブジェクトを生成するにはnew クラス名()
とします。
クラスから生成されたオブジェクトのことを「 インスタンス」と呼びます。
先ほど用意したBarcelonaクラスからインスタンスを生成してみます。
class Barcelona {
}
//インスタンスを生成し、定数に代入
const barca = new Barcelona();
Barcelonaクラスから生成されたインスタンスをBarcelonaインスタンスと呼びます。
生成したインスタンスは、定数などに代入して用いられます。
この状態で定数barcaを出力すると空のオブジェクトが出力されます。
#コンストラクタ
「コンストラクタ」とは、classによって生成されるオブジェクトの生成や初期化を行う機能です。
コンストラクタはクラスで1つしか定義できません。
クラスの{ }
の中にconstructor() { }
と書くことで定義することができます。
class Barcelona {
//コンストラクタの定義
constructor() {
処理
}
}
const barca = new Barcelona();
コンストラクタの{ }
の中には、処理を記述します。
ここに書いた処理は、インスタンスが生成された直後に実行されます。
また、コンストラクタの処理はインスタンスが生成されるたびに毎回実行されます。
コンストラクタに処理を書いてみます。
class Barcelona {
constructor() {
//コンストラクタの処理
console.log('Hola!');
}
}
const barca = new Barcelona();
//Hola!
コンストラクタの中に「Hola!」と出力する処理を書いてみました。
インスタンスを生成した後に、ファイルを実行するとコンソールにはコンストラクタの中に書いた処理が実行されました。
##プロパティと値を追加する
クラスの目的はオブジェクトを生成することなので、プロパティと値を追加する方法を学びます。
コンストラクタの中でthis.プロパティ名 = 値
とすることで、生成されたインスタンスにプロパティと値を追加することができます。
また、インスタンスはオブジェクトなので、コンストラクタの中で追加した値は、インスタンス.プロパティ
とすることでクラスの外で使用することができます。
練習でname
プロパティにMessi
と追加してみます。さらにそれを出力します。
class Barcelona {
constructor() {
this.name = 'Messi';
}
}
const barca = new Barcelona();
//生成したインスタンスを出力
console.log(barca);
//{name: Messi}
//追加した値の出力
console.log(barca.name);
//Messi
コードを見てみていきます。
constructor
の中でthis.name = 'Messi';
とすることで、{name: 'Messi'}
というオブジェクトが生成されています。
次にconst barca = new Barcelona();
でbarca
インスタンスを生成しています。constructor
はインスタンスが生成された時に走るので、この時点でconstructor
の中で定義した{name: 'Messi'}
が生成されます。
そのため、生成したbarca
インスタンスを出力すると、{name: 'Messi'}
と表示されます。
また、barca.name
とすることで、値を取り出すこともできています。
##コンストラクタに引数を渡す
コンストラクタの()
内では引数を受け取るができます。関数と同じように、()
の中に引数名を記述することで、その引数をコンストラクタの処理内で使用できます。
引数を渡すには、インスタンスを生成する際のクラス名のあとの()
に値を追加します。
先ほどの例を引数を使ってアップデートします。
class Barcelona {
//引数を受け取る
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
}
//引数を渡す
const barca = new Barcelona('Messi', 10);
//それぞれの値を取り出す
console.log(barca.name);
//Messi
console.log(barca.uniformNumber);
//10
コードを見てみます。
先ほどと変わった部分は、constructor
の定義部分です。引数にname
とuniformNumber
を渡すように書き換えています。
そのため、インスタンスを生成する際には、const barca = new Barcelona('Messi', 10);
というように2つの引数を渡して生成しなければいけません。
出力は、先ほどの例と同様の結果が得られます。
#メソッド
「メソッド」とは、クラスの動作を定義するものになります。
class構文の中では、クラスに対して自由にメソッドを定義できます。このクラスに定義したメソッドは作成したインスタンスが持つ動作となります。
実はconstructor
は、初期化時に呼ばれる特殊なメソッドです。constructor
では、情報としてプロパティを設定しました、メソッドでは動作を設定します。
メソッドはクラスの{ }
の中でメソッド名() { }
とすることで定義できます。メソッドは関数のようなもので、{ }
の中に処理を書きます。
処理の部分では、return
を用いて値を返すこともできます。
メソッドを呼び出す際は、インスタンス.メソッド名()
とします。
先ほどの例に、introduce
メソッドを追加し、呼び出します。
class Barcelona {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
//メソッドの定義
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
}
const barca = new Barcelona('Messi', 10);
//メソッドの呼び出し
barca.introduce();
//FC Barcelonaの背番号10はMessiです
では、変わった部分をみていきましょう。
class
内でintroduce
メソッドを定義しています。
処理の中身は、引数で受け取った値が入ったオブジェクトを使って、「FC Barcelonaの背番号〇〇は△△です」とコンソールに表示させる処理を書いています。
このようにメソッド内でインスタンスの値を使うときは、this.プロパティ名
とすることで定数や変数のように扱うことができます。
インスタンスの生成時には、2つの引数を渡します。
barca.introduce();
でクラスで定義したメソッドを呼び出しています。メソッドの中で書いた処理が実行され、「FC Barcelonaの背番号10はMessiです」と出力されます。
#メソッド内でメソッドを使う
メソッド内で他のメソッドを呼び出すにはthis.メソッド名()
と書きます。
今回は例として、先ほどの例に新しいメソッドを追加して、それを呼び出してみます。
class Barcelona {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
//新しいメソッドを定義
introduceAdd() {
console.log('FC Barcelonaの選手紹介');
//メソッド内でメソッドを使う
this.introduce();
}
}
const barca = new Barcelona('Messi', 10);
//新しく作成したメソッドを呼び出す
barca.introduceAdd();
// FC Barcelonaの選手紹介
// FC Barcelonaの背番号10はMessiです
追加したコードを見ていきます。
introduceAdd
というメソッドを定義しています。introduceAdd
内では、introduce
メソッドを呼び出すために、 this.introduce();
としています。
introduceAdd
メソッドを呼び出して実行すると、しっかりと処理が実行されました。
#クラス式
「クラス式」とは、クラスを定義するもう一つの方法です。
クラス式を用いると、名前なしでクラスを定義することができます。
書き方は関数式のように、定数や変数にクラスを代入します。
これまでのコードをクラス式で書き換えてみましょう。
//クラス式でクラスを定義
let Barcelona = class {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
}
const barca = new Barcelona('Messi', 10);
console.log(barca.name);
コードの変わった部分をみてみます。
これまでclass Barcelona {}
と定義していたところを、let Barcelona = class { }
と書き換えました。
その他は変更はありません。
コードは問題なく実行されます。
#クラスの継承
「継承」とは、すでにあるクラスをもとに新しくクラスを作成する方法のことです。
継承元になるクラスを親クラス、新しく作成するクラスを子クラスと呼び、class 子クラス名 extends 親クラス { }
と書きます。
Barcelona
クラスを継承してForward
クラスを作成してみます。
class Barcelona {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
}
//クラスを継承
class Forward extends Barcelona {
}
//インスタンスを生成
const forward = new Forward('Messi', 10);
//継承したメソッドを呼び出す
forward.introduce();
//FC Barcelonaの背番号10はMessiです
コードの変更部分を見てみましょう。
class Forward extends Barcelona { }
でクラスを継承しています。定義したクラスの中には何も処理を書いていません。
その後、Forward
クラスからforward
インスタンスを生成しています。この時、親クラスに書かれているconstructor
では引数を2つ受け取るので、インスタンスを生成する際にも2つの引数を渡します。
forward.introduce();
で継承したメソッドを呼び出しています。Forward
クラスの中では、何も処理を記述していませんが、Barcelona
クラスを継承しているので、introduce
メソッドを使うことができます。
このように、作成した子クラスは、親クラスの全ての機能を引き継いでいるため、親クラスに定義されているメソッドを使用することができます。
##メソッドの追加
継承して作成した子クラスにも、独自のソッドを追加することができます。
子クラスで定義した独自のメソッドは、親クラスから呼び出すことは出来ないので注意しましょう。
先ほどの例で、子クラスにメソッドを追加してみます。
class Barcelona {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
}
class Forward extends Barcelona {
//独自のメソッドを追加
introducePosition() {
console.log('ポジションはFWです');
}
}
//インスタンスを生成しメソッドを呼び出す
const forward = new Forward('Messi', 10);
forward.introducePosition();
//ポジションはFWです
コードを見てみましょう。
Barcelona
クラスを継承したForward
クラスの中でintroducePosition() { }
というメソッドを記述しています。このメソッドでは、ポジション紹介をコンソールに出力する処理を書いています。
先ほどの例と同じくforward
インスタンスを生成します。
最後に、forward.introducePosition();
でメソッドを呼び出します。すると、メソッドの処理が実行され、コンソールに文章が出力されます。
##オーバーライド
###メソッドのオーバーライド
子クラスにすでに親クラスに存在するメソッドと同じ名前のメソッドを定義すると、子クラスのメソッドが優先して使用されます。
これを「オーバーライド」と呼び、子クラスのメソッドが親クラスのメソッドを上書きしています。
先ほどの例で、introduceメソッドをオーバーライドしてみます。
class Barcelona {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
}
class Forward extends Barcelona {
//introduceメソッドをオーバーライド
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
//introducePositionメソッドを追加
this.introducePosition();
}
introducePosition() {
console.log('ポジションはFWです');
}
}
//インスタンスを生成しメソッドを呼び出す
const forward = new Forward('Messi', 10);
forward.introduce();
// FC Barcelonaの背番号10はMessiです
// ポジションはFWです
変わった部分を見ると、子クラスであるForward
クラスの中で、親クラスの中でも定義されているintroduce
メソッドの中身を書き換えています。
このメソッドをforward.introduce();
として呼び出すと、追加で書いた処理も実行されていることがわかります。
今この状態では、Barcelona
クラスの中のintroduce
メソッドとForward
クラスの中のintroduce
メソッドが存在するわけですが、同じメソッドでも実行される処理は違うという状態になっています。
###コンストラクタのオーバーライド
コンストラクタもオーバーライドすることができます。
オーバーライドすることで、子クラスにプロパティを追加したりすることができます。
子クラスでコンストラクタをオーバーライドする際は、1行目にsuper()
と記述します。
このsuper()
の部分が親クラスのコンストラクタを呼び出しています。
そのため、親クラスのコンストラクタが引数を受け取る場合は、super
の後ろの( )
の中に引数を渡す必要があります。
これまでの例に、position
プロパティを追加してみます。それに伴い、メソッドの内容も少し書き換えます。
class Barcelona {
constructor(name, uniformNumber) {
this.name = name;
this.uniformNumber = uniformNumber;
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
}
}
class Forward extends Barcelona {
//コンストラクタをオーバーライド
constructor(name, uniformNumber) {
super(name, uniformNumber);
this.position = 'FW'
}
introduce() {
console.log(`FC Barcelonaの背番号${this.uniformNumber}は${this.name}です`);
this.introducePosition();
}
//positionプロパティを使用
introducePosition() {
console.log(`ポジションは${this.position}です`);
}
}
const forward = new Forward('Messi', 10);
forward.introduce();
// FC Barcelonaの背番号10はMessiです
// ポジションはFWです
//インスタンスを出力
console.log(forward);
//{ name: 'Messi', uniformNumber: 10, position: 'FW' }
変更部分をみてみます。
Forward
クラスにコンストラクタを追加しました。
コンストラクタの中では、まずsuper(name, uniformNumber);
と書くことで、親クラスのコンストラクタを呼び出しています。
これに、this.introducePosition();
と書くことで、プロパティと値を追加しています。
実際に生成したforward
インスタンスをconsole.log(forward);
といて出力すると、子クラスで追加したプロパティと値が追加されたオブジェクトが表示されます。
#まとめ
今回は以上となります。
コードが長くなってくると混乱してくるので、少しずつ理解していきましょう。
最後まで読んでいただきありがとうございました。ではまた。