classを使ったクラスの定義とオブジェクト指向プログラミングの基本をわかりやすく解説

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
~
ad. 価格範囲を指定して商品を探せます

classの概要

クラス定義 JavaScript予約語

class

概要 classは、JavaScriptにおいてオブジェクト指向プログラミング(OOP)を実現するための最重要キーワードです。
データ(プロパティ)とそのデータに対する具体的な処理(メソッド)を1つのまとまりとして定義し、同じ構造を持つオブジェクトを効率的に大量生産するための共通のテンプレート(設計図)として機能します。

わかりやすく説明 classは、一言で言えば「たい焼きの『型』」です。
型(クラス)をあらかじめ1つ定義しておけば、そこから同じ形をした本物のたい焼き(オブジェクト)を何個でも簡単に生み出すことができます。

  • 内部に constructor(コンストラクタ)と呼ばれる特殊な初期化関数を持つことができ、生成時に固有のデータをオブジェクトに埋め込めます。
  • extends キーワードを使用することで、別のクラスが持つ機能や性質をそのまま引き継ぐ「継承」という強力な仕組みを利用できます。
  • JavaScriptのクラスは完全に新しい仕組みではなく、従来の「プロトタイプ(prototype)ベース」のオブジェクト生成を、他言語のように見やすく書き直した構文糖衣(シンタックスシュガー)です。

classの基本的な使い方

クラスを定義する際は、class クラス名 { } の中に、初期化を行う constructor と、そのオブジェクトが持つ具体的な処理(メソッド)を並べて記述します。
定義したクラスから実際のオブジェクトを生成する際は、必ず new キーワードを頭に付けて呼び出します。
以下は、動物の設計図を作成し、そこから個別のオブジェクトを生み出す基本的な例です。

// Animalという名前の設計図(クラス)を定義します
class Animal {
    // newされた瞬間に最初に一度だけ自動実行される初期化部屋です
    constructor(name) {
        this.name = name; // 生成されるオブジェクト自身(this)に名前を保存します(プロパティ)
    }

    // この設計図から生まれたオブジェクトが自由に使える共通の関数(メソッド)です
    speak() {
        console.log(`${this.name} が鳴いています。`);
    }
}

// 設計図を元に、本物のオブジェクト(インスタンス)を生成します
const dog = new Animal("ポチ");
dog.speak(); // 出力: ポチ が鳴いています。
  • クラスの中で定義した変数(プロパティ)にアクセスする際は、自分自身を指し示す this を頭に付与するのが必須のルールです。
  • クラスから new によって生み出された実体オブジェクトのことを、専門用語で「インスタンス(Instance)」と呼びます。

クラスの継承

既存のクラスが持つ共通の機能をすべてベースとして引き継ぎつつ、さらに新しい機能を追加したり、一部の処理を専用に上書き(オーバーライド)した拡張版の設計図を作りたい場合は extends を使用します。
以下は、共通の動物クラスを引き継ぎながら、犬専用の鳴き声に処理を上書きする例です。

// 親となる基本の動物クラス
class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} が鳴いています。`);
    }
}

// Animalの能力を100%引き継いだ、子となる「犬(Dog)」クラスを作成します
class Dog extends Animal {
    // 親クラスが持つメソッドと「全く同じ名前」で中身を上書き(オーバーライド)します
    speak() {
        console.log(`${this.name} がワンワンと鳴いています。`);
    }
}

// 子クラスのオブジェクトを作成
const dog = new Dog("ポチ");
dog.speak(); // 出力: ポチ がワンワンと鳴いています。(子で上書きした専用メソッドが優先されます)
  • extends を活用することで、同じようなコードを何度も複製して書く必要がなくなり、コードの再利用性とメンテナンス性が飛躍的に向上します。
  • 子クラス側で特別な処理を追加しない場合は、親クラスの constructor が自動的に呼び出されてデータが引き継がれます。

静的メソッド

通常、クラスの中のメソッドは new して作った個別のインスタンスから呼び出しますが、オブジェクト個別ではなく「設計図そのものに直接紐づく関数」を作りたい場合は、頭に static(スタティック)を付与します。
これを静的メソッドと呼び、インスタンスを作らなくても クラス名.メソッド名() で直接実行することができます。

// 静的メソッドをまとめた便利クラス
class MathUtils {
    // staticを付けることで、クラス直属の便利関数になります
    static add(a, b) {
        return a + b;
    }
}

// newでインスタンスを作る必要はありません!クラスから直接呼び出せます
console.log(MathUtils.add(5, 10)); // 出力: 15

// ❌ 逆に、newしたインスタンスからstaticメソッドを呼ぼうとするとエラーになります
// const utils = new MathUtils();
// utils.add(5, 10); // 🛑 TypeError: utils.add is not a function
  • 静的メソッドは、個別のオブジェクトが持つ固有のデータ(this.name など)を一切使用しない、計算処理や共通のユーティリティ関数をまとめるのに最適です。
  • JavaScriptに標準で組み込まれている Math.max() や Array.isArray() なども、この static メソッドと全く同じ仕組みで提供されています。

注意点

  • クラス名の規則(パスカルケース): クラス名は、通常の変数や関数(キャメルケース)と明確に区別するため、頭文字を大文字で始める「パスカルケース(例: MyClass)」で記述するのが開発者間の絶対的な共通ルールとなっています。
  • ホイスティング(巻き上げ)が適用されない: function キーワードで作った通常の関数は、コードの下部に書いてあっても上部から呼び出すことができます(巻き上げ現象)。
    しかし、class には巻き上げが起きないため、必ず「クラスを定義した行よりも下」でなければ new を実行することはできません。

    // ❌ NGな例:定義する前に対象のクラスを呼び出すことはできません
    const pet = new Animal("ポチ"); // 🛑 ReferenceError: Cannot access 'Animal' before initialization
    
    class Animal {}
    
  • ES6未対応環境とモダンブラウザ: 現代の主要なブラウザや実行環境(Node.jsなど)では class はそのまま動作しますが、数十年前の極めて古いインターネット環境をサポートしなければならない現場では、トランスパイラ(例: Babel)を用いて従来のプロトタイプ型コードに自動変換させる必要があります。

よくある質問

Q: クラスのプロパティを、constructor を使わずに直接クラスのトップレベルに記述することはできますか?
A: はい、モダンなJavaScript(ES2022以降)では「クラスフィールド(パブリッククラスフィールド)」という機能が標準化されたため、コンストラクタを通さずに直接プロパティの初期値を宣言できるようになりました。

// クラスフィールドを使用した最新の記述例
class Counter {
    count = 0; // constructorを使わずに直接初期値を定義できます

    increment() {
        this.count++;
    }
}
Q: クラスを使うと何が便利ですか?ただの連想配列オブジェクトでは駄目なのですか?
A: ECサイトの商品データやゲームのキャラクターのように、「全く同じデータ構造とメソッドを持つ実体を、10個、100個と量産したい」というケースにおいて、クラスは劇的な効果を発揮します。
連想配列を量産すると同じ数だけメモリが浪費されますが、クラスを使えば共通処理(メソッド)のメモリが設計図側に1箇所に集約されるため、動作が軽量になり、後からの機能修正も一括で行えるため保守性が桁違いに向上します。
Q: 継承(extends)した子クラス側で、親クラスの元のメソッドや初期化処理を途中で呼び出す方法はありますか?
A: super キーワードを使用します。
子クラスのコンストラクタ内で親のコンストラクタを呼び出すときは super() と記述し、親クラスのメソッドを呼び出したいときは super.speak() のように記述することで、親の持っていた元の機能を再利用しつつ独自の肉付けを行うことができます。

// superを用いた親クラス初期化の強制例
class Cat extends Animal {
    constructor(name, color) {
        super(name); // ❗ 子クラスにconstructorを書く場合は、必ず最初にsuper()を実行しなければならないルールです
        this.color = color;
    }
}

まとめ

classは、関連するデータと処理を1つのテンプレートにまとめ上げ、複雑になりがちなプログラムを美しく整理整頓するための非常に強力な仕組みです。

  • 共通の構造を定義する「クラス(設計図)」と、そこから new で生み出される「インスタンス(実体)」の関係性を正しく頭に入れましょう。
  • extends による継承や、super による親機能の呼び出し、static による静的関数を使いこなすことで、大規模なアプリ開発にも耐えうる柔軟な設計ができるようになります。
  • 近年の仕様アップデート(クラスフィールドなど)による進化も押さえつつ、効率的でバグの出にくいクリーンなオブジェクト指向開発を進めていきましょう。