How do I use a static variable in ES6 class?

前端 未结 5 538
故里飘歌
故里飘歌 2021-02-05 04:11

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

相关标签:
5条回答
  • 2021-02-05 04:50

    Static class-side properties and prototype data properties must be defined outside of the ClassBody declaration.

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

    class Animal {
    
      static increaseCount() {
        Animal.count += 1;
      }
    
      static getCount() {
        return Animal.count;
      }
    }
    
    Animal.count = 0;
    
    Animal.increaseCount();
    console.log(Animal.getCount()); // undefined

    0 讨论(0)
  • 2021-02-05 04:50

    To set a static variable, set it on the object Animal itself. As of now in Javascript you cannot directly declare static properties inside classes like you can declare static methods.

    class Animal {
        constructor() {
        }
    
        static increaseCount() {
            this.count += 1;
        }
    
        static getCount() {
            return this.count;
        }
    }
    Animal.count = 0;
    console.log(Animal.increaseCount());
    console.log(Animal.getCount()); 
    
    0 讨论(0)
  • 2021-02-05 04:59

    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.

    0 讨论(0)
  • 2021-02-05 05:04

    you can use closures to simulate static variables

    const Animal= (() => {
        let count= 0;
    
        class Animal {
            constructor() {}
    
            static increaseCount() {
                count += 1;
            }
    
            static getCount() {
                return count;
            }
        }
    
        return Animal;
    })();
    
    console.log(Animal.getCount());
    Animal.increaseCount();
    console.log(Animal.getCount());

    0 讨论(0)
  • As mentioned in other answers, this.count refers to instance property in constructor. In order for static property to be initialized, Animal.count should be set.

    Class fields proposal provides syntactic sugar for Animal.count = 0 that is available with transpilers (Babel, etc):

    class Animal {
      static count = 0;
      ...
    }
    

    An alternative in ES6 is to use initial values, in this case Animal.count initial value doesn't need to be set explicitly, e.g.:

    class Animal {    
      static increaseCount() {
        this.count = this.getCount() + 1;
      }
    
      static getCount() {
        return this.count || 0;
      }
    }
    

    Accessor methods aren't welcome in JavaScript classes - this is what getter/setter descriptors are for:

    class Animal {    
      static increaseCount() {
        this.count += 1;
      }
    
      static get count() {
        return this._count || 0;
      }
    
      static set count(v) {
        this._count = v;
      }
    }
    

    Static-only class is considered antipattern in JavaScript because a state or other traits that are specific to classes aren't used. In case there should be only one instance, plain object should be used (unless there are other concerns that could benefit from class):

    const animal = {    
      increaseCount() {
        this.count += 1;
      },
    
      get count() {
        return this._count || 0;
      },
    
      set count(v) {
        this._count = v;
      }
    };
    
    0 讨论(0)
提交回复
热议问题