How do I use a static variable in ES6 class?

parksb picture parksb · Jul 17, 2018 · Viewed 63.2k times · Source

I'm trying to use a static variable in es6. I'd like to declare a static variable count in Animal class and increase it. However, I couldn't declare a static variable through static count = 0;, so I tried another way like this:

I expected console.log(Animal.getCount()); to be 1, but it doesn't work. How do I declare a static variable and modify it by calling a method?

Answer

T.J. Crowder picture T.J. Crowder · Jul 17, 2018

Your class has no static variables (if by static variable you mean static property). getCount returns NaN (after you call increaseCount) because Animal has no count property initially. Then increaseCount does undefined + 1 which is NaN. Instances created by new Animal have a count property initially, but Animal itself does not until you call increaseCount. this within a static method refers to the Animal class (constructor function) itself (if you call it via Animal.methodName(...)).

You could give Animal a count property:

Animal.count = 0;

Live Example:

class Animal {
  constructor() {
  }

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

  static getCount() {
    return this.count;
  }
}
Animal.count = 0;

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

With the static class fields proposal (currently at Stage 3), you could do that declaratively with static count = 0; in Animal. Live Example (Stack Snippets' Babel configuration seems to support it):

class Animal {
  constructor() {
  }

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

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

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

With the private static proposal (at Stage 3 and actively being implemented), you could even make count private:

class Animal {
  constructor() {
  }

  static #count = 0;

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

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

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

Stack Snippets' Babel config doesn't support that, but you can run it live in their REPL.


Side note: Using this within a static method to refer to the class (constructor function) is a bit tricky if there are subclasses, because for instance, if you had:

class Mammal extends Animal {}

and then

Mammal.increaseCount();

this within increaseCount (which it inherits from Animal) refers to Mammal, not Animal.

If you want that behavior, use this. If you don't, use Animal in those static methods.