7.4 クラスの継承

クラスの強力な機能の一つに、他のクラスの機能を引き継ぐことができる「継承(けいしょう)」があります。

共通の機能を、親クラス(基底クラス)にまとめ、子クラス(派生クラス)では独自の機能を追加したり、親クラスのメソッドを上書き(オーバーライド)したりできます。共通で必要な機能を親クラスにまとめることで、子クラスでは、親クラスとの差分だけを記述していけばいいことになります。

extends キーワード

子クラスが親クラスを継承する際に使用します

super キーワード

子クラスのコンストラクタ内で、親クラスのコンストラクタを呼び出す際に使用します。

メソッドのオーバーライド

子クラスで、親クラスが持つ同名のメソッドを定義すると、機能を上書きすることができます。

7.4.1 クラスの継承を用いたプログラム

クラスの継承やオーバーライドを用いて JavaScript を記述するやり方を学んでみましょう。

ソースフォルダ:public/ch07

ファイル名:class-inheritance.js

➢ class-inheritance.html

前の項で作った ch07/class.html をコピーし、ch07 にペーストしてください。
その際に、ファイル名を class-inheritance.html に変更します。
ファイル内の class.html や class.js の記述も、class-inheritance.html や class-inheritance.js に修正します。

➢ class-inheritance.js

// class-inheritance.js

// 親クラス:動物全般のクラス
class Animal {
    constructor(name) {
        this.name = name;
    }
    speak() {
        return `${this.name}が音を出しました。`;
    }
}

// 子クラス:犬クラス(Animalを継承)
class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 親クラスのコンストラクタを呼び出します
        this.breed = breed; // 犬種という独自のプロパティを追加
    }
    // メソッドのオーバーライド(上書き)
    speak() {
        return `${this.name}(${this.breed})が吠えました!`;
    }
}

const myDog = new Dog("バディ", "ゴールデンレトリバー");
alert(`継承の結果: ${myDog.speak()}`);

実行結果

解説

4 行目で、class というキーワードを用いて Animal という名前の新しいクラスを定義しています。
ここまでは前項で学習した内容ですが、speak()メソッドの中で返却されるメッセージに注目してください。

4:   class Animal {
5:       constructor(name) {
6:           this.name = name;
7:       }
8:       speak() {
9:           return `${this.name}が音を出しました。`;
10:     }
11: }

続く 14 行目で extends というキーワードを使い、Animal という親クラスの機能をすべて引き継いだ Dog という新しいクラスを定義しています。

14: class Dog extends Animal {
15:     constructor(name, breed) {
16:         super(name); // 親クラスのコンストラクタを呼び出します
17:         this.breed = breed; // 犬種という独自のプロパティを追加
18:     }
19:     // メソッドのオーバーライド(上書き)
20:     speak() {
21:         return `${this.name}(${this.breed})が吠えました!`;
22:     }
23: }

新しい Dog クラスの constructor には breed(犬種)という新しい引数を追加しました。しかし name に関しては super(name) で親クラスである Animal のコンストラクタを呼び出すことで、名前の設定を親クラスに任せています。

さらに 20 行目では、親クラスの speak() メソッドを同じ名前で違う内容に書き直しています。

これがオーバーライド(上書き)です。親クラスの speak() に従えば、最後に表示されるメッセージは「バディが音を出しました。」になるはずですが、Dog クラスで speak()メソッドをオーバーライドしたため「バディ(ゴールデンレトリバー)が吠えました!」に変更されています。

7.4.2 instanceof 演算子

あるオブジェクトが「どのクラスから作られたか」を確認するには instanceof 演算子を使います。

書式:instanceof 演算子

オブジェクト instanceof クラス名

前項の Animal / Dog クラスを使って確認してみましょう。

const dog = new Dog("バディ", "ゴールデンレトリバー");

alert(dog instanceof Dog); // true:dog は Dog クラスから作られた
alert(dog instanceof Animal); // true:Dog は Animal を継承しているため
alert(dog instanceof Object); // true:すべてのオブジェクトは Object のインスタンス

継承関係にある親クラスに対しても true を返す点がポイントです。dog は Dog のインスタンスであると同時に、Animal のインスタンスでもあると判定されます。

typeof は文字列・数値・真偽値などの基本的な型の確認に使い、クラスのインスタンスかどうかの確認には instanceof を使います。この 2 つを組み合わせることで、ほとんどの型チェックが対応できます。

なお、10 章で学ぶ try-catch のエラーハンドリングでは、以下のように instanceof を使ってエラーの種類を判定することもあります。

catch (error) {
    if (error instanceof TypeError) {
        alert("型のエラーです");
    } else if (error instanceof RangeError) {
        alert("範囲外のエラーです");
    }
}