JavaScriptのクラスでは、インスタンスメソッドやstaticメソッド、アクセッサプロパティなどを用いて、クラスの動作や機能を定義することができます。

しかし、全く0の状態からいくつものクラスを作成するのではなく、あるクラスの内容をそのまま再利用して新しいクラスを作りたいという場合もあるでしょう。

そこで今回は、クラス(Class)と継承について解説していきます。

クラスの継承

「クラスの継承」とは、あるクラスの内容を引き継いで新しいクラスを作成することです。
内容を引き継ぐ側を「親クラス」と呼び、引き継ぎを受けて新しいクラスを作成する側を「子クラス」と呼びます。

クラスの継承には、「extends」というキーワードを使います。

class Childclass extends Parentclass {}

例えば、シェフというクラスの内容を、中華料理専門のシェフに継承すると以下のようになります。

class Chef {
  constructor(name, experty) {
    this.name = name;
    this.experty = experty;
  }
  info() {
    console.log(`${this.name}さんは、${this.experty}のシェフです`);
  }
}

class ChineseChef extends Chef {}
const chinesechef = new ChineseChef('王', '中華料理');
chinesechef.info();
//"王さんは、中華料理のシェフです"

ChineseChefクラスは、すでに定義されているChefクラスのコンストラクタのデフォルトを使用しているので、短いコードでプロパティやメソッドを使用することができます。

子クラスにメソッドを追加

親クラスから継承した後に、子クラスだけに使用したいメソッドを追加することができます。

class Chef {
  constructor(name, experty) {
    this.name = name;
    this.experty = experty;
  }
  info() {
    console.log(`${this.name}さんは、${this.experty}のシェフです`);
  }
}

class ChineseChef extends Chef {
  //新しくメソッドを定義
  experience() {
    console.log(`${this.name}さんは、${this.experty}店を開業して20年です`);
  }
}
const chinesechef = new ChineseChef('王', '中華料理');
chinesechef.info();
chinesechef.experience();

実行結果

//"王さんは、中華料理のシェフです"
//"王さんは、中華料理店を開業して20年です"

ChineseChefクラスだけに使用するexperienceメソッドの追加によって、新たな情報を出力することができました。

このように、クラスの継承を利用すると、親クラスから拾える内容はできるだけ使い回し、子クラスだけが持つ内容を追加することができます。

オーバーライド

「オーバーライド」とは、引き継がれた内容を、独自のものに上書きすることです。
クラスは継承するだけでなく、「super」というキーワードを用いて、親クラスのコンストラクタやメソッドの内容を上書きすることができます。

子クラスの中で、コンストラクタやメソッドの1行目に「super」を記述します。

//親クラス
class Parentclass {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  method() {
  }
}

//クラスの継承(子クラス)
class Childclass extends Parentclass {
  constructor(x, y) {
    //親クラスのコンストラクタの呼び出し
    super(x, y);
  }
  method() {
    //親クラスのメソッドの呼び出し
    super.method();
  }
}

では、実際の例を見ていきましょう。

以下は、シェフという親クラスを元に、日本料理のシェフという子クラスを作成しています。
親クラスで定義しているプロパティやメソッドを呼び出し、再定義をします。

「super」のキーワードに注目してください。

class Chef {
  constructor(props) {
    this.name = props.name;
    this.experty = props.experty;
    this.position = props.position;
  }
  intro() {
    console.log(`${this.name}さんは、${this.experty}の${this.position}です`);
  }
}

class JapaneseChef extends Chef {
  //子クラスのconstructorを再定義
  constructor(props) {
    super(props); //親クラスのpropsの呼び出し
    this.repertoire = props.repertoire || []; //repertoireを追加
  }
  menu() {
    console.log(`${this.name}さんのおすすめメニューは、${this.repertoire}です`);
  }
  //子クラスのintroメソッドを再定義
  intro() {
    super.intro(); //親クラスのintroメソッドの呼び出し
    this.menu(); //menuメソッドを呼び出し
  }
}

const japanesechef = new JapaneseChef({
  name: '佐藤毅',
  experty: '日本料理',
  position: '人気シェフ',
  repertoire: ['そば', '刺身定食', 'カツ丼']
});
japanesechef.intro();

実行結果

//"佐藤毅さんは、日本料理の人気シェフです"
//"佐藤毅さんのおすすめメニューは、そば,刺身定食,カツ丼です"

親クラスのChefには、名前・専門・ポジション(name, experty, position)というプロパティと、シェフを紹介するためのメソッド(intro)が用意されています。
ここまでが基準となる親クラスで定義されているものです。

続いて、子クラスのJapaneseChefを見てみましょう。
親クラスのプロパティを「super(props)」で呼び出した後、子クラスだけが持つ「this.repertoire」を追加しています。
また、親クラスのメソッドを「super.intro()」で呼び出した後に、子クラスだけが持つ「menu()」メソッドを追加しているもの分かります。

これで、「佐藤毅さんは、日本料理の人気シェフです」という自己紹介と、「佐藤毅さんのおすすめメニューは、そば,刺身定食,カツ丼です」というメニューのレパートリーを出力することができました。

まとめ

今回は、クラス(Class)の継承方法について解説しました。

元の型を継承することができれば、短いコードで新しいクラスを作成することができるため、可読性が上がります。
また、継承を利用することで、共通の内容をできる限り1箇所にまとめることができ、メンテナンスの面にも貢献できます。

これらの内容を踏まえ、クラス構文を使ってプログラムを書く際に、クラスの継承も取り入れてみてください。

クラス(Class)のおさらい