JavaScript | ES6+ 文法:クラス構文 – 静的メソッド

JavaScript JavaScript
スポンサーリンク

静的メソッドとは何か(まずイメージから)

静的メソッド(static メソッド)は、
「インスタンスではなく“クラスそのもの”に属するメソッド」 です。

普通のメソッドはこう呼びます。

const user = new User("Alice");
user.greet();      // インスタンスから呼ぶ
JavaScript

静的メソッドはこう呼びます。

User.fromJson("...");  // クラス名から直接呼ぶ
Math.max(1, 2, 3);     // これも静的メソッドの一種
JavaScript

Math.max には「Math のインスタンス」はいりませんよね。
「個々のインスタンスに紐づかない、“クラスに関する便利な処理”」をまとめる場所
それが静的メソッドです。

基本構文と普通のメソッドとの違い

どう書くのか

class の中で、メソッドの前に static を付けるだけです。

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

  greet() {               // インスタンスメソッド
    console.log(`Hi, ${this.name}`);
  }

  static createGuest() {  // 静的メソッド
    return new User("Guest");
  }
}

const u1 = new User("Alice");
u1.greet();               // インスタンスから呼ぶ

const guest = User.createGuest(); // クラスから呼ぶ
guest.greet();                    // 作られたインスタンスを使う
JavaScript

ここが重要です。
インスタンスメソッド:u.greet() のようにインスタンスから呼ぶ
静的メソッド:User.createGuest() のようにクラス名から呼ぶ

「使い方」がそもそも違うと押さえておいてください。

this の中身が全然違う

インスタンスメソッド内の this は「そのインスタンス」ですが、
静的メソッド内の this は「クラス(その関数自体)」を指します。

class Example {
  constructor() {
    this.value = 123;
  }

  showInstance() {
    console.log("instance this.value:", this.value);
  }

  static showStatic() {
    console.log("static this:", this);
  }
}

const e = new Example();

e.showInstance();  // instance this.value: 123
Example.showStatic(); // static this: [class Example] みたいな形
JavaScript

静的メソッドでは「特定のインスタンス」ではなく「クラス全体」に関する情報・処理を扱う、
と意識すると this の違いに納得がいきます。

どんなときに静的メソッドを使うのか(考え方)

インスタンスを「作るための工場メソッド」

よくある使い方は、インスタンス生成の便利関数です。

class User {
  constructor(name, admin = false) {
    this.name = name;
    this.admin = admin;
  }

  describe() {
    console.log(`${this.name} (${this.admin ? "管理者" : "一般"})`);
  }

  static createAdmin(name) {
    return new User(name, true);
  }

  static createGuest() {
    return new User("Guest", false);
  }
}

const u1 = User.createAdmin("Alice");
const u2 = User.createGuest();

u1.describe(); // Alice (管理者)
u2.describe(); // Guest (一般)
JavaScript

ここが重要です。
「よく使うインスタンスの作り方」を静的メソッドとして名前付きで用意しておくと、
使う側が new User(...) の細かいルールを知らなくても、安全にインスタンスを作れます。

インスタンスに依存しない「ユーティリティ的な処理」

個々のユーザーには関係なく、「ユーザーという概念に関する処理」を書きたいときにも使えます。

class PasswordUtil {
  static isStrong(password) {
    return password.length >= 8 && /[0-9]/.test(password);
  }
}

console.log(PasswordUtil.isStrong("abc"));     // false
console.log(PasswordUtil.isStrong("abc12345"));// true
JavaScript

わざわざ new PasswordUtil() としてインスタンスを作る必要はないですよね。
このような「状態を持たない、ただの計算・チェック」系は静的メソッドと相性が良いです。

そのクラスに属する「共通の情報・定数」を扱う

例えば、インスタンス数をカウントする、バージョン情報を返す、など。

class Counter {
  static count = 0; // クラス全体で共有するフィールド

  constructor() {
    this.id = ++Counter.count;
  }

  static getTotalCount() {
    return Counter.count;
  }
}

const c1 = new Counter();
const c2 = new Counter();

console.log(c1.id);                 // 1
console.log(c2.id);                 // 2
console.log(Counter.getTotalCount()); // 2
JavaScript

ここが重要です。
「個々のインスタンスの状態」ではなく、「クラス全体で共有する状態」を扱う場所として静的メソッド(+静的フィールド)が使える
と考えると、使いどころが見えてきます。

静的メソッドとインスタンスメソッドをどう使い分けるか

判断基準は「その処理はインスタンスに依存するか?」

例えば User クラスで考えます。

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

  sendEmail(subject, body) {
    // このユーザーの email に送る
    console.log(`To: ${this.email}, ${subject}`);
  }

  static validateEmail(email) {
    return email.includes("@");
  }
}
JavaScript

sendEmail特定のユーザーの email アドレス に送る処理なので、インスタンスメソッド。
validateEmail文字列(email)が正しい形かどうか を判定するだけなので、インスタンスは不要 → 静的メソッド。

ここが重要です。
「this(インスタンスの状態)が必要な処理」→ インスタンスメソッド
「this が不要な処理」→ 静的メソッド

というシンプルな判断でほとんどの場合うまくいきます。

「全部静的メソッドでいいじゃん?」と思ったとき

確かに、クラスの中に全部 static で書くこともできます。
ただそれは、クラスというより「名前空間付きの関数集」になってしまいます。

インスタンスメソッドを使うと、

  • this を通じてオブジェクトの状態を持てる
  • 「状態と振る舞い」がセットになって、扱いやすくなる

静的メソッドは、

  • インスタンスに紐付かない処理を、クラスの“周辺”にまとめておける

という役割分担です。
両者を意識的に使い分けることで、クラス設計がぐっと読みやすくなります。

継承と静的メソッド(super との関係も)

静的メソッドも継承される

親クラスの静的メソッドは、子クラスからも使えます。

class Animal {
  static isAnimal(obj) {
    return obj instanceof Animal;
  }
}

class Dog extends Animal {}

const d = new Dog();
console.log(Animal.isAnimal(d)); // true
console.log(Dog.isAnimal(d));    // true(Dog からも呼べる)
JavaScript

DogAnimal を継承しているので、静的メソッドも引き継ぎます。

親の静的メソッドを上書き・拡張する

子クラスで同じ名前の静的メソッドを定義すると、オーバーライドできます。
その際に super も使えます。

class Animal {
  static describeClass() {
    console.log("Animal クラス");
  }
}

class Dog extends Animal {
  static describeClass() {
    super.describeClass(); // 親の静的メソッド
    console.log("Dog クラス");
  }
}

Dog.describeClass();
// Animal クラス
// Dog クラス
JavaScript

ここが重要です。
インスタンスメソッドの継承と同じように、静的メソッドも「継承される」「オーバーライドできる」「super で親を呼べる」
という点は頭に入れておくと、他人のコードが読みやすくなります。

よくある勘違いと注意点(ここを押さえておくと楽)

静的メソッドはインスタンスから呼べない

これ、最初によくやります。

class User {
  static hello() {
    console.log("Hello");
  }
}

const u = new User();

u.hello();       // TypeError: u.hello is not a function
User.hello();    // 正しい呼び方
JavaScript

静的メソッドは インスタンスには存在しません
あくまで「クラスオブジェクト(User)にぶら下がっている関数」です。

静的メソッドの中でインスタンスの this は使えない

静的メソッドの中の this は「クラス」なので、
this.name のようなインスタンスプロパティはありません。

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

  static bad() {
    console.log(this.name); // ここでの this はクラス(User)、インスタンスではない
  }
}

const u = new User("Alice");
User.bad();  // undefined(期待した結果にならない)
JavaScript

「インスタンスのプロパティを使いたいなら、それは静的メソッドではない」
と考えて、インスタンスメソッドにすべきです。

例題で静的メソッドの感覚を固める

例1:ID 採番するクラス

class IdGenerator {
  static current = 0;

  static next() {
    this.current++;
    return this.current;
  }
}

console.log(IdGenerator.next()); // 1
console.log(IdGenerator.next()); // 2
console.log(IdGenerator.next()); // 3
JavaScript

インスタンスを作る必要がない「機能だけのクラス」です。
クラス全体で共有したい状態(current)と、それを操作する静的メソッド(next)を持っています。

例2:文字列ユーティリティをクラスでまとめる

class StringUtil {
  static toCamel(str) {
    return str.replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
  }

  static toKebab(str) {
    return str.replace(/[A-Z]/g, ch => "-" + ch.toLowerCase());
  }
}

console.log(StringUtil.toCamel("user-name"));  // userName
console.log(StringUtil.toKebab("userName"));   // user-name
JavaScript

インスタンスはいらないが、「文字列操作系」をひとまとめにしたい場合に静的メソッドが便利です。

例3:JSON からの復元を静的メソッドにまとめる

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

  describe() {
    console.log(`${this.id}: ${this.name}`);
  }

  static fromJson(jsonStr) {
    const obj = JSON.parse(jsonStr);
    return new User(obj.id, obj.name);
  }
}

const json = '{"id":1,"name":"Alice"}';
const user = User.fromJson(json);
user.describe(); // 1: Alice
JavaScript

静的メソッド fromJson を通すことで、
「JSON から User をどう復元するか」というロジックをクラス側に閉じ込められます。

まとめ

静的メソッドの核心は、
「インスタンスではなく、“クラスそのもの”に属するメソッド。クラス名から直接呼ぶ」 という点です。

押さえておきたいポイントは次のとおりです。

  • static メソッド名() { ... } で定義し、クラス名.メソッド名() で呼ぶ
  • インスタンスメソッドとは違い、インスタンスではなくクラスに紐づく
  • インスタンスに依存しない処理(ユーティリティ、工場メソッド、クラス共通状態の扱い)に向いている
  • 静的メソッドは継承され、子クラスでオーバーライドしたり super で親を呼んだりできる
  • インスタンスからは呼べないし、静的メソッド内の this は「インスタンス」ではない

まずは、自分で作ったクラスに
「1つ静的メソッドを足してみる」ところから始めてみてください。
“インスタンスに属さないけど、このクラスの仲間として置いておきたい処理”が見えてきたとき、
静的メソッドの気持ちよさを実感できるはずです。

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