ES6 クラスで静的変数を使用するにはどうすればいいですか? 質問する

ES6 クラスで静的変数を使用するにはどうすればいいですか? 質問する

es6 で静的変数を使用しようとしています。クラスcountで静的変数を宣言Animalして増やしたいのですが、 を通じて静的変数を宣言できなかったのでstatic count = 0;、次のような別の方法を試しました。

class Animal {
  constructor() {
    this.count = 0;
  }

  static increaseCount() {
    this.count += 1;
  }

  static getCount() {
    return this.count;
  }
}

console.log(Animal.increaseCount()); // undefined
console.log(Animal.getCount()); // NaN

console.log(Animal.getCount());になると思っていました1が、うまくいきません。静的変数を宣言し、メソッドを呼び出して変更するにはどうすればよいでしょうか?

ベストアンサー1

注記: クラスの可変staticプロパティは、サブクラスが関係する場合に問題になることがあります。詳細については、回答の最後を参照してください。

クラスには静的変数がありません (静的変数が静的プロパティを意味する場合)。には最初はプロパティがないため、を呼び出した後にgetCountが返されます。次に である を実行し、それを に割り当てます。NaNincreaseCountAnimalcountincreaseCountundefined + 1NaNAnimal.countインスタンスによって作成された は最初は プロパティnew Animalを持っていますcountが、Animalを呼び出すまでそれ自体は プロパティを持っていませんincreaseCount。メソッドthis内では、クラス (コンストラクター関数) 自体staticを参照しますAnimal( 経由で呼び出す場合Animal.methodName(...))。

クラスに静的プロパティを与えるには、staticキーワードを使用して宣言します (クラス フィールドの提案¹ が広く実装されたため)。

class Animal {
    static count = 0;

    static increaseCount() {
        ++this.count;
    }

    static getCount() {
        return this.count;
    }
}

Animal.increaseCount();
console.log(Animal.getCount());
Animal.increaseCount();
console.log(Animal.getCount());

必要に応じて、静的メンバーをプライベートにして、外部からアクセスできないようにすることもできますAnimal

class Animal {
    static #count = 0;

    static increaseCount() {
        ++this.#count;
    }

    static getCount() {
        return this.#count;
    }
}

Animal.increaseCount();
console.log(Animal.getCount());
Animal.increaseCount();
console.log(Animal.getCount());


上記の警告に関して:thisサブクラスがある場合、静的メソッド内でクラス (コンストラクター関数) を参照するのは少し注意が必要です。たとえば、次のような場合です。

class Mammal extends Animal {}

その後

Mammal.increaseCount();

thisincreaseCount( から継承されるAnimal)は ではなく を参照しMammalますAnimal

class Animal {
    static count = 0;

    static increaseCount() {
        ++this.count;
    }

    static getCount() {
        return this.count;
    }
}

class Mammal extends Animal {
}

console.log(Object.hasOwn(Mammal, "count")); // false
// This call *reads* from `Animal.count` (because `Mammal` doesn't have a
// `count` yet), but *writes* to `Mammal.count`, potentially causing
// confusion.
Mammal.increaseCount();
console.log(Object.hasOwn(Mammal, "count")); // true
console.log(Mammal.getCount()); // 1
// This time, both the read and write use `Mammal.count`
Mammal.increaseCount();
console.log(Mammal.getCount()); // 2
console.log(Animal.getCount()); // 0 - nothing ever wrote to it

もし、あんたが欲しいその動作がthis必要な場合は、 を使用してください。そうでない場合は、それらのメソッドAnimalでを使用してください。static

最後に、プライベート フィールドを作成すると、次の内容を書き込むことができないため、経由してcount呼び出すと失敗することに注意してください。increaseCountMammalMammalAnimal.#count

class Animal {
    static #count = 0;

    static increaseCount() {
        ++this.#count;
    }

    static getCount() {
        return this.#count;
    }
}

class Mammal extends Animal {
}

Mammal.increaseCount();
// ^^^^^^^^^^^^^^^−−− TypeError: Cannot read private member #count from an
// object whose class did not declare it


¹ のクラスフィールドこの提案は、当初は別々だった複数の提案を統合したものでした。プライベートインスタンスメソッドとアクセサクラスのパブリックインスタンスフィールドとプライベートインスタンスフィールド静的クラスフィールドとプライベート静的メソッド

おすすめ記事