JavaScript初心者でも分かる!classを使った便利な実装テクニック

JavaScriptのclassを使いこなせるようになりたい!でも難しそう…。そんな悩みを持つ方も多いのではないでしょうか?

実はclassを使うと、コードがすっきりと整理され、メンテナンスも楽になります。この記事では、実践的な例を交えながら、classの基礎から活用方法までをやさしく解説します。

これを読めば、あなたもclassを使った効率的なコーディングができるようになります!

クラスとは何か?

JavaScriptのclassは、オブジェクト指向プログラミングの考え方を取り入れた機能です。似た性質を持つデータとその処理方法をひとまとめにできる便利な「設計図」のようなものです。

たとえば、ECサイトでユーザー情報を管理する場合を考えてみましょう:

JS
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }

  // ユーザー情報を表示するメソッド
  showProfile() {
    return `名前: ${this.name}, メール: ${this.email}`;
  }
}

// 使用例
const user = new User('山田太郎', 'yamada@example.com');
console.log(user.showProfile());  // "名前: 山田太郎, メール: yamada@example.com"

このように、classを使うことで関連するデータと機能を1つにまとめることができ、コードの見通しが良くなります。

次の章では、このclassの基本的な書き方について詳しく見ていきましょう。

クラスの基本構文

クラスの基本的な書き方を見ていきましょう。クラスを宣言するには class キーワードを使います。

コンストラクタ

JS
class Dog {
  // コンストラクタ(初期化処理)
  constructor(name, age) {
    this.name = name;  // プロパティの設定
    this.age = age;    // プロパティの設定
  }

  // メソッド(クラスの中で定義する関数)
  bark() {
    return `${this.name}が吠えました!`;
  }
}

クラスの使用方法

JS
// クラスからインスタンスを作成
const pochi = new Dog('ポチ', 3);

// メソッドの呼び出し
console.log(pochi.bark());  // "ポチが吠えました!"
console.log(pochi.name);    // "ポチ"
console.log(pochi.age);     // 3

ポイント:

  • constructorは特別なメソッドで、インスタンス作成時に自動的に実行されます
  • thisはインスタンス自身を指します
  • プロパティはインスタンスごとに固有の値を持ちます
  • メソッドはすべてのインスタンスで共有されます

クラスの継承

クラスの継承を使うと、既存のクラスの機能を引き継ぎながら、新しい機能を追加できます。

JS
// 基底クラス(親クラス)
class Animal {
  constructor(name) {
    this.name = name;
  }
  
  makeSound() {
    return "...";
  }
}

// Animalクラスを継承した子クラス
class Cat extends Animal {
  constructor(name, color) {
    super(name);  // 親クラスのコンストラクタを呼び出し
    this.color = color;
  }

  makeSound() {
    return "にゃー!";  // メソッドのオーバーライド
  }

  scratch() {
    return `${this.color}の${this.name}が引っかきました`;
  }
}

// 使用例
const tama = new Cat('タマ', '白');
console.log(tama.makeSound());  // "にゃー!"
console.log(tama.scratch());    // "白のタマが引っかきました"

重要ポイント:

  • extendsで継承を実装
  • super()で親クラスのコンストラクタを呼び出し
  • 子クラスで同名メソッドを定義すると上書き(オーバーライド)される
  • 親クラスのメソッドと新しいメソッドの両方が使える

クラスの重要な機能

staticメソッド

インスタンス化せずに使えるクラスメソッドを定義できます。

JS
class Calculator {
  static add(a, b) {
    return a + b;
  }
}

console.log(Calculator.add(5, 3));  // 8
// インスタンス化不要で直接使用可能

getterとsetter

プロパティのアクセスと設定を制御できます。

JS
class BankAccount {
  #balance = 0;  // プライベートフィールド

  get balance() {
    return `¥${this#balance}`;
  }

  set balance(value) {
    if (value < 0) {
      throw new Error('残高はマイナスにできません');
    }
    this.#balance = value;
  }
}

const account = new BankAccount();
account.balance = 1000;
console.log(account.balance);  // "¥1000"

プライベートフィールド

#記号を使って、クラス外からアクセスできないプロパティを定義できます。

  • 外部からの不正なアクセスを防ぐ
  • カプセル化を実現

これらの機能を使うことで、より安全で保守性の高いコードが書けます。

実践的な使用例

実際のプロジェクトでよく使用される具体例を見てみましょう:

JS
// ショッピングカートの実装例
class ShoppingCart {
  #items = [];

  addItem(item) {
    this.#items.push(item);
  }

  removeItem(itemId) {
    this.#items = this.#items.filter(item => item.id !== itemId);
  }

  get totalPrice() {
    return this.#items.reduce((sum, item) => sum + item.price, 0);
  }

  checkout() {
    if (this.#items.length === 0) {
      throw new Error('カートが空です');
    }
    return {
      items: this.#items,
      total: this.totalPrice,
      date: new Date()
    };
  }
}

// 使用例
const cart = new ShoppingCart();
cart.addItem({ id: 1, name: 'Tシャツ', price: 2000 });
cart.addItem({ id: 2, name: 'ジーンズ', price: 5000 });

console.log(cart.totalPrice);  // 7000
console.log(cart.checkout());  // { items: [...], total: 7000, date: ... }

このように、クラスを使うことで:

  • データ(商品)と処理(追加・削除・会計)を1つにまとめられる
  • プライベートフィールドで内部データを保護
  • getterで合計金額の計算を自動化
  • メソッドで複雑な処理をカプセル化

実務では、このような形でクラスを活用することが多いでしょう。

よくある落とし穴と対処法

1. thisの挙動の問題

JS
class Timer {
  constructor() {
    this.seconds = 0;
  }

  start() {
    // 問題のあるコード
    setInterval(function() {
      this.seconds++;  // thisがWindowを指してしまう
    }, 1000);

    // 正しい実装
    setInterval(() => {
      this.seconds++;  // アロー関数でthisを保持
    }, 1000);
  }
}

2. 継承時の注意点

JS
class Parent {
  constructor() {
    this.init();  // 初期化メソッド
  }
}

class Child extends Parent {
  // 問題: superの呼び出し忘れ
  constructor() {
    // super()を呼び出す必要がある
    this.name = 'Child';  // エラー発生
  }
}

// 正しい実装
class Child extends Parent {
  constructor() {
    super();  // 親のコンストラクタを先に呼び出す
    this.name = 'Child';  // OK
  }
}

これらの問題は初心者がよく遭遇するものです。特にthisの挙動には注意が必要で、アロー関数を使うことで多くの問題を解決できます。

まとめ

クラスの使用は、モダンなJavaScriptプログラミングの重要なスキルです。

クラス使用のベストプラクティス

  1. 単一責任の原則を守る(1つのクラスは1つの役割に集中)
  2. プライベートフィールドを活用してデータを保護
  3. getterとsetterで適切なデータアクセス制御を実装
  4. 継承は必要な場合のみ使用(過度な継承は避ける)

従来のプロトタイプベースとの比較

JS
// 従来のプロトタイプベース
function User(name) {
  this.name = name;
}
User.prototype.sayHi = function() {
  return `Hi, ${this.name}!`;
};

// モダンなクラス構文
class User {
  constructor(name) {
    this.name = name;
  }
  sayHi() {
    return `Hi, ${this.name}!`;
  }
}

クラス構文を使うことで:

  • コードが読みやすくなる
  • オブジェクト指向的な設計が容易に
  • 他の言語経験者にも理解しやすい

この記事で学んだ知識を活かして、ぜひ実践的なコード作成に挑戦してみてください!