JavaScriptのクラスと継承【プログラミング初心者向け教材】

プログラミング

プログラミングをチームで効率よく開発するためには、担当領域を決めたり、似たようなコードが作らないようにするなどの工夫が必要となります。

プログラムを役割や機能に応じて分割することをモジュール分割と言ったりしますが、その際に必要となる概念がクラスです。

適切なクラス分割を行うことで、無駄がなくて読みやすく、メンテナンスのしやすいプログラムにすることができます。

プログラミング初心者にとっては、理解が難しい分野ではありますが、チームで開発するプログラマとなるためには必須の知識となります。

本記事では、JavaScriptのクラスと継承についてまとめます。

プログラミング初心者の方の学習や、忘れてしまった方の復習として、参考にしていただければ幸いです。

記載しているプログラムは、Node.js14.14.0を使って動作確認をしています。

JavaScriptのクラスと継承

JavaScriptのクラスと継承について、以下の内容を採り上げます。

  • クラスの定義方法
  • コンストラクタ
  • インスタンス化
  • メソッド定義
  • プロパティ定義
  • 静的メソッド定義
  • クラスの継承

クラスの定義方法

クラスとは、動作(メソッド)や状態(プロパティ)を持つ構造(オブジェクト)です。

JavaScriptでクラスが導入されたのは、ECMAScript Edtion 6(ES2015)からとなります。
2020年現在においては、多くのブラウザで利用することができ、Node.jsでも扱うことができます。

クラスを定義するには、class 文として宣言します。
例えばPersonクラスを宣言するには、以下のように記述します。

class Person {
}

コンストラクタ

コンストラクタは、そのクラスからインスタンスを作成(後述)した際に、最初に実行されるメソッドです。
通常はクラスの初期化をする処理が記述されます。

クラスには必ずコンストラクタが必要で、記述しないと空のコンストラクタが自動的に作成されます。

コンストラクタを定義するには、constructorメソッドを定義します。

class Person {
    constructor() {
    }
}

インスタンス化

定義したクラスを利用するためには、インスタンス化する必要があります。
インスタンス化とは実体を作ることで、クラス定義は実体を作るための雛形やテンプレートのようなもので、インスタンス化すると実物が作成されるというイメージです。

インスタンス化するには new 演算子を使います。
以下の例では、Personクラスをインスタンス化して、personという変数に代入しています。

const person = new Person();

メソッド定義

クラスにおけるメソッドの役割は、そのクラスの動作(振る舞い)を定義するものになります。
例えば、Person(人間)クラスであれば、歩く、食べる、寝るという動作がクラスとしてのメソッドになります。

class Person {
    constructor() {
    }
    walk() {
        console.log("歩きます");
    }
    eat() {
        console.log("食べます");
    }
}

上記のクラス定義をインスタンス化して実行すると、以下のようになります。

const person = new Person();
person.walk(); // -> 歩きます
person.eat(); // -> 食べます

プロパティ定義

クラスにはプロパティ(属性値)を持つことができます。
例えば、Person(人間)クラスであれば、年齢、身長、体重という属性値がプロパティとなります。

プロパティはコンストラクタで設定したり、アクセッサを使って設定することができます。

コンストラクタで設定

コンストラクタで設定すると、インスタンス作成時に異なる属性値を持つインスタンスを作成することができます。

class Person {
    constructor(age, height, weight) {
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
    walk() {
        console.log("歩きます");
    }
    eat() {
        console.log("食べます");
    }
}

上記のクラス定義をインスタンス化してプロパティ値を取得すると、以下のようになります。

const person = new Person(30, 170, 60);
console.log(person.age); // -> 30
console.log(person.height); // -> 170
console.log(person.weight); // -> 60

アクセッサで設定

プロパティへの代入(setter)と参照(getter)を併せてアクセッサと呼びます。

アクセッサを使ってプロパティを操作するには、プロパティ名(メソッド名)の前に get または set をつけます。
setterには値を設定するための引数が必要となります。
getterには必ず値を返す return文 が必要となります。

class Person {
    constructor(age, height, weight) {
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
    walk() {
        console.log("歩きます");
    }
    eat() {
        console.log("食べます");
    }
    get name() {
        return this._name;
    }
    set name(n) {
        this._name = n;
    }
}

上記のクラス定義をインスタンス化して、nameプロパティに対して値を設定し、取得すると以下のようになります。

const person = new Person(30, 170, 60);
person.name = "名前";
console.log(person.name); // -> 名前

静的メソッド定義

クラスをインスタンス化しなくても利用できるメソッドを静的メソッド(staticメソッド)と呼びます。

静的メソッドとして定義するには、メソッド名の前に static をつけます。
例えば、Personクラスを元にクローンを作り出す of という静的メソッドを定義するには、以下のようになります。

class Person {
    constructor(age, height, weight) {
        this.age = age;
        this.height = height;
        this.weight = weight;
    }
    walk() {
        console.log("歩きます");
    }
    eat() {
        console.log("食べます");
    }
    get name() {
        return this._name;
    }
    set name(n) {
        this._name = n;
    }
    static of(person) {
        return new Person(person.age, person.height, person.weight);
    }
}

上記の静的メソッドを利用するには、以下のようになります。

const person = new Person(30, 170, 60);
const clone = Person.of(person);
console.log(clone.age); // -> 30
console.log(clone.height); // -> 170
console.log(clone.weight); // -> 60

クラスの継承

クラスの継承とは、あるクラスを引き継いで新たなクラスを定義することです。
引き継ぎ元のクラスを親クラス(基底クラス、スーパークラス)と呼び、引き継ぎ先のクラスを子クラス(派生クラス、サブクラス)と呼びます。

子クラスを定義するには、extends を使って以下のように定義します。

class Child extends Person {
}

小クラスは親クラスのメソッドやプロパティを継承しているため、インスタンス化した際にそのまま呼出すことができます。

const child = new Child(1, 70, 10);
child.walk(); // -> 歩きます
child.eat(); // -> 食べます
console.log(child.age); // -> 1
console.log(child.height); // -> 70
console.log(child.weight); // -> 10
child.name = "赤ちゃん";
console.log(child.name); // -> 赤ちゃん

親クラスが持つメソッドを同じメソッド名で処理を書き換える(オーバーライド)こともできます。
例えば、walkメソッドを以下のようにオーバーライドします。

class Child extends Person {
    walk() {
        console.log("ハイハイをします");
    }
}

インスタンス化して、walkメソッドを呼出すと以下のようになります。

const child = new Child(1, 70, 10);
child.walk(); // -> ハイハイをします

親クラスが持つメソッドやプロパティには、super を使って呼出すことができます。

class Child extends Person {
    eat() {
        super.eat();
    }
}

const child = new Child(1, 70, 10);
child.eat(); // -> 食べます

良いプログラマになるにはクラス設計が重要

プログラマは単にプログラミングするだけではなく、設計ができることも重要です。

チームで効率よく開発を進めるには、どんなクラス設計、継承関係、クラス間連携とするのかは重要な要素です。

クラス分割をしたり、オブジェクト指向でプログラミングするのは難しいかもしれませんが、普段から目に見えるものがどんな関係があるか、どんな振る舞いを持っているのかを考えてみると良い訓練になると思います。

 

今回はJavaScriptのクラスと継承についてまとめました。

以上、参考になれば幸いです。

コメント

タイトルとURLをコピーしました