static

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.

static キーワードは、クラスに静的メソッドや静的プロパティを定義します。静的メソッドも静的プロパティもクラスのインスタンスからは呼び出されません。その代わりに、クラスそのものから呼び出されます。静的メソッドは多くの場合、オブジェクトの生成や複製を行う関数などのユーティリティ関数です。静的プロパティはキャッシュ、固定的な構成、その他の各インスタンスに複製する必要のないデータです。

静的メソッドは多くの場合、オブジェクトの生成や複製を行う関数などのユーティリティ関数です。静的プロパティはキャッシュ、固定的な構成、その他の各インスタンスに複製する必要のないデータです。

メモ: クラスの文脈において、 MDN Web Docs のコンテンツではプロパティとフィールドという用語を同等のものとして使用しています。

試してみましょう

構文

js
class ClassWithStatic {
  static staticField;
  static staticFieldWithInitializer = value;
  static staticMethod() {
    // …
  }
}

それ以外にも構文上の制約があります。

  • 静的プロパティ(フィールドまたはメソッド)の名前を prototype とすることはできません。
  • クラスフィールド(静的またはインスタンス)の名前を constructor とすることはできません。

解説

このページでは、静的メソッド、静的アクセサ、静的フィールドを含む、クラスのパブリック静的プロパティを紹介します。

パブリック静的機能は、static キーワードを使用して宣言します。これらはクラス評価時に、 [[DefineOwnProperty]] の意味づけ(これは本質的に Object.defineProperty() です)を使用して、クラスのコンストラクターに追加されます。これらは、コンストラクターから再びアクセスします。

静的メソッドの多くは、インスタンスを作成したり複製したりするなどの、ユーティリティ関数です。パブリック静的フィールドは、作成するすべてのクラスインスタンスではなく、クラスごとに一つだけフィールドを存在させたい場合に有益です。これは、キャッシュや固定の構成値、 あるいはインスタンスをまたがって複製する必要のないデータなどに有益です。

静的フィールド名は計算できます。計算式の this 値はクラス定義の周囲の this であり、クラス名を参照すると、クラスがまだ初期化されていないため ReferenceError になります。この式では awaityield は期待どおりに動作します。

静的フィールドは初期化子を持つことができます。初期化子を持たない静的フィールドは undefined に初期化されます。パブリック静的フィールドはサブクラスでは再初期化されませんが、プロトタイプチェーン経由でアクセスすることができます。

js
class ClassWithStaticField {
  static staticField;
  static staticFieldWithInitializer = "静的フィールド";
}

class SubclassWithStaticField extends ClassWithStaticField {
  static subStaticField = "サブクラスのフィールド";
}

console.log(Object.hasOwn(ClassWithStaticField, "staticField")); // true
console.log(ClassWithStaticField.staticField); // undefined
console.log(ClassWithStaticField.staticFieldWithInitializer); // "静的フィールド"
console.log(SubclassWithStaticField.staticFieldWithInitializer); // "静的フィールド"
console.log(SubclassWithStaticField.subStaticField); // "サブクラスのフィールド"

フィールド初期化子では、 this は現在のクラス(その名前からもアクセスすることができます)を参照し、 super は基底クラスのコンストラクターを参照します。

js
class ClassWithStaticField {
  static baseStaticField = "基底クラスの静的フィールド";
  static anotherBaseStaticField = this.baseStaticField;

  static baseStaticMethod() {
    return "基底クラスの静的フィールドの出力";
  }
}

class SubClassWithStaticField extends ClassWithStaticField {
  static subStaticField = super.baseStaticMethod();
}

console.log(ClassWithStaticField.anotherBaseStaticField); // "基底クラスの静的フィールド"
console.log(SubClassWithStaticField.subStaticField); // "基底クラスの静的フィールドの"

式は同期的に評価されます。初期化子式で(awaityield)を使用することはできません。(初期化子式は暗黙に関数に包まれていると考えてください)。

静的フィールド初期化子と静的初期化ブロックは、 1 つずつ評価されます。フィールド初期化子は、それより上のフィールド値を参照することはできますが、それより下のフィールド値を参照することはできません。静的メソッドはすべて事前に追加され、アクセスすることができますが、初期化されるフィールドより下のフィールドを参照している場合、呼び出すと期待した動作をしないことがあります。

メモ: これはプライベート静的フィールドではより重要です。初期化されていないプライベートフィールドにアクセスすると、たとえそのプライベートフィールドが下で宣言されていたとしても、 TypeError が発生するからです。(プライベートフィールドが宣言されていない場合は、早期に SyntaxError となります。)

クラスでの静的メンバーの使用

次の例はいくつかのことを説明しています。

  1. 静的メンバー(メソッドまたはプロパティ)がクラスでどのように定義されるか
  2. 静的メンバーを持つクラスがサブクラスを作れるか
  3. 静的メンバーがどう呼び出せて、どう呼び出せないか
js
class Triple {
  static customName = "Tripler";
  static description = "I triple any number you provide";
  static calculate(n = 1) {
    return n * 3;
  }
}

class SquaredTriple extends Triple {
  static longDescription;
  static description = "I square the triple of any number you provide";
  static calculate(n) {
    return super.calculate(n) * super.calculate(n);
  }
}

console.log(Triple.description); // 'I triple any number you provide'
console.log(Triple.calculate()); // 3
console.log(Triple.calculate(6)); // 18

const tp = new Triple();

console.log(SquaredTriple.calculate(3)); // 81 (not affected by parent's instantiation)
console.log(SquaredTriple.description); // 'I square the triple of any number you provide'
console.log(SquaredTriple.longDescription); // undefined
console.log(SquaredTriple.customName); // 'Tripler'

// This throws because calculate() is a static member, not an instance member.
console.log(tp.calculate()); // 'tp.calculate is not a function'

静的メンバーの別な静的メソッドからの呼び出し

同じクラス内の静的メソッドまたはプロパティを静的メソッドから呼び出すには、 this キーワードを使います。

js
class StaticMethodCall {
  static staticProperty = "static property";
  static staticMethod() {
    return "Static method and " + this.staticProperty + " has been called";
  }
  static anotherStaticMethod() {
    return this.staticMethod() + " from another static method";
  }
}
StaticMethodCall.staticMethod();
// 'Static method and static property has been called'

StaticMethodCall.anotherStaticMethod();
// 'Static method and static property has been called from another static method'

クラスのコンストラクターや他のメソッドからの静的メソッドの呼び出し

静的メソッドは静的ではないメソッドの this キーワードを使用して直接アクセスすることができません。呼び出すにはクラス名を使用して クラス名.静的メソッド名() / クラス名.静的プロパティ名 のようにするか、 constructor プロパティのメソッドとして this.constructor.静的メソッド名() / this.constructor.静的プロパティ名 のようにしてください。

js
class StaticMethodCall {
  constructor() {
    console.log(StaticMethodCall.staticProperty); // 'static property'
    console.log(this.constructor.staticProperty); // 'static property'
    console.log(StaticMethodCall.staticMethod()); // 'static method has been called.'
    console.log(this.constructor.staticMethod()); // 'static method has been called.'
  }

  static staticProperty = "static property";
  static staticMethod() {
    return "static method has been called.";
  }
}

仕様書

Specification
ECMAScript Language Specification
# sec-class-definitions

ブラウザーの互換性

BCD tables only load in the browser

関連情報