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
が返されます。次に である を実行し、それを に割り当てます。NaN
increaseCount
Animal
count
increaseCount
undefined + 1
NaN
Animal.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();
this
increaseCount
( から継承される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
呼び出すと失敗することに注意してください。increaseCount
Mammal
Mammal
Animal.#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
¹ のクラスフィールドこの提案は、当初は別々だった複数の提案を統合したものでした。プライベートインスタンスメソッドとアクセサ、クラスのパブリックインスタンスフィールドとプライベートインスタンスフィールド、静的クラスフィールドとプライベート静的メソッド。