概要
JavaScriptは元々プロトタイプベースの言語だが、ES6以降 class
構文が導入され、**クラスベースのOOP(オブジェクト指向プログラミング)**がより書きやすくなった。
しかし、構文をなぞるだけでは不十分。
「いつ class を使うべきか」「extends や super の設計責任は何か」など、設計レベルでの判断基準が必要となる。
この記事では、構文解説にとどまらず、クラス構文が担うべき責務とその正しい使い所を体系的に整理する。
対象環境
ES6 以降(Node.js / モダンブラウザ)
class構文の基本
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
}
const u = new User('toto');
u.greet(); // Hello, toto
constructor:インスタンス初期化の入口
class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
}
- ✅ 自動的に
new
で呼ばれる - ✅ インスタンス生成時に一度だけ実行される
- ❌
return
でオブジェクトを返すと、this
は無効化される
extends / super:継承と親クラスへのアクセス
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a sound`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 親のconstructorを呼び出す
this.breed = breed;
}
speak() {
return `${this.name} barks`;
}
}
const d = new Dog('Max', 'Shiba');
d.speak(); // Max barks
✅ superとは
-
super()
は親の constructor を呼び出す - メソッド内で
super.method()
によって親のメソッドを上書きしつつ呼び出すことも可能
クラス設計における責務の切り方
要素 | 担当すべき責務 |
---|---|
constructor |
インスタンスの最小完全構成の定義 |
メソッド | インスタンスに属する処理の提供 |
静的メソッド | インスタンスに依存しない汎用処理 |
継承 | インターフェースの統一 / 特化の分離 |
static:インスタンスを持たないクラスの関数群
class MathUtil {
static double(x) {
return x * 2;
}
}
MathUtil.double(3); // 6
- ✅ 状態を持たない「関数集合体」として使える
- ❌ インスタンスとは分離されるため、状態にアクセスできない
getter / setter:アクセス制御と表現力の向上
class Rectangle {
constructor(w, h) {
this.w = w;
this.h = h;
}
get area() {
return this.w * this.h;
}
set width(val) {
if (val < 0) throw new Error('Invalid width');
this.w = val;
}
}
const r = new Rectangle(3, 4);
console.log(r.area); // 12
抽象クラス風の使い方(JSには正式な抽象クラスはない)
class AbstractService {
fetch() {
throw new Error('must implement fetch()');
}
}
class RealService extends AbstractService {
fetch() {
return 'real data';
}
}
→ ✅ 設計上の“制約”として class を利用できる
よくある誤解
❌ 関数ベースと class ベースは同じ?
→ ✅ 振る舞いは似ているが、設計意図が異なる
- 関数ベース:一時的な処理
- クラスベース:構造と責任をもった永続的な振る舞い
class構文を使うべき設計条件
条件 | class構文を使うべきか? |
---|---|
インスタンスごとに状態を持つ | ✅ Yes |
状態に基づいて動的な処理を行う | ✅ Yes |
汎用の関数群を定義したい | ❌ No → functionで十分 |
状態不要 / 設計不要なデータ変換 | ❌ No → モジュール関数へ |
結語
JavaScriptのクラス構文は、「OOP風」な糖衣構文ではない。
それは 状態を伴う構造を明示し、再利用性と抽象性を担保する“設計のための記法” である。
- 継承は、振る舞いを共通化するための道具
- constructorは、最小責務を与えるための入口
- メソッドは、状態の操作手段であり、機能の境界である
構文に振り回されるのではなく、設計に沿って構文を選ぶこと。
それがOOPにおけるクラスの、本来の意味である。