【问题标题】:How do I use a static variable in ES6 class?如何在 ES6 类中使用静态变量?
【发布时间】:2018-12-25 04:33:54
【问题描述】:

我正在尝试在 es6 中使用静态变量。我想在Animal 类中声明一个静态变量count 并增加它。但是,我无法通过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,但它不起作用。 如何声明静态变量并通过调用方法对其进行修改?

【问题讨论】:

标签: javascript ecmascript-6 es6-class


【解决方案1】:

您的类没有静态变量(如果静态变量是指静态属性)。 getCount 返回 NaN(在您调用 increaseCount 之后),因为 Animal 最初没有 count 属性。然后increaseCount 执行undefined + 1NaN。由new Animal 创建的实例 最初有一个count 属性,但Animal 本身没有,直到您调用increaseCountthisstatic 方法中指的是Animal 类(构造函数)本身(如果您通过Animal.methodName(...) 调用它)。

你可以给Animal一个count属性:

Animal.count = 0;

现场示例:

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());

使用 static class fields proposal(目前处于第 3 阶段),您可以在 Animal 中使用 static count = 0; 以声明方式执行此操作。 Live Example (Stack Snippets 的 Babel 配置似乎支持它)

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());

通过private static 提案(处于第 3 阶段并正在积极实施),您甚至可以将count 设为私有:

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 配置不支持,但您可以在 their REPL 中实时运行它。


旁注:如果有子类,在静态方法中使用this 来引用类(构造函数)有点棘手,因为例如,如果你有:

class Mammal extends Animal {}

然后

Mammal.increaseCount();

increaseCount 中的this(它继承自Animal)指的是Mammal,而不是Animal

如果您想要这种行为,请使用this。如果不这样做,请在那些 static 方法中使用 Animal

【讨论】:

  • Animal 类中是否允许static count = 0;?它导致SyntaxError: Unexpected token。我正在将 Babel 与 Webpack 一起使用。
  • @Caesium133 - 正如我上面所说,这是 static class fields proposal 的一部分,目前处于流程的第 3 阶段(因此,它还没有在规范中,引擎只是现在才寻找添加它)。
  • 怎么把increaseCount放到新Animal的构造函数中?归根结底,这难道不是人们通常想要在课堂上设置柜台的原因吗?看来你没有展示这种情况。 (我想count 应该是一个集合的属性,而不是实例类 - 将计数作为类的静态属性是一种“低预算”集合,嗯?
  • static count = 0; 这些天似乎在工作……我在做梦吗?但是,它与 Java 的 static 有很大的不同
  • @OhadR - 不,你不是在做梦。 :-) V8(在 Chrome、Node.js、Brave、Chromium、新 Edge 等中)和 SpiderMonkey(在 Firefox 75+ 中)都开始支持 static 公共字段。 Safari 仍在进行中。
【解决方案2】:

要设置静态变量,请将其设置在对象 Animal 本身上。到目前为止,在 Javascript 中,您不能像声明静态方法那样直接在类中声明静态属性。

class Animal {
    constructor() {
    }

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

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

【讨论】:

    【解决方案3】:

    静态类端属性和原型数据属性必须在 ClassBody 声明之外定义。

    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

    【讨论】:

    • 没关系,但最后一行代码返回 1 ,不是未定义的。这可能会误导新手
    • 今天不用再在外面申报了
    【解决方案4】:

    正如其他答案中提到的,this.count 指的是constructor 中的 instance 属性。为了初始化static属性,应该设置Animal.count

    Class fields proposalAnimal.count = 0 提供语法糖,可用于转译器(Babel 等):

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

    ES6 中的另一种选择是使用初始值,在这种情况下,Animal.count 初始值不需要显式设置,例如:

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

    在 JavaScript 类中不欢迎访问器方法 - 这就是 getter/setter 描述符的用途:

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

    仅静态类在 JavaScript 中被视为反模式,因为不使用特定于类的状态或其他特征。如果应该只有一个实例,则应该使用普通对象(除非有其他问题可以从class 中受益):

    const animal = {    
      increaseCount() {
        this.count += 1;
      },
    
      get count() {
        return this._count || 0;
      },
    
      set count(v) {
        this._count = v;
      }
    };
    

    【讨论】:

    • 但是你的getter和setter函数不是Accessor方法吗?
    • 你的 getCount 不是 Accessor 方法吗?
    • 带有 getter 和 setter 的 Animal 类返回 0:let b = new Animal; console.log(Animal.count);
    • 我想说更有用的是,您的带有 get/set 的类应该在创建新实例时自增。如果 _count == 0,您的最终对象样式实际上不会返回 _count 的值。当 _count 实际上未定义时,它会返回 0。这是一个错误的结果。我认为这是一个错误。由于该对象需要在外部将 count 初始化为 0,因此它似乎与仅使用变量没有什么不同。行为与变量没有什么不同的对象是否被视为反模式?
    • @johnywhy 感谢您的注意,有一个错字,应该是 this.count 而不是 this._count in increaseCount 和除 get/set count 之外的其他成员。 get count() { return this._count || 0 }_count: 0, get count() { return this._count } 基本相同。我更喜欢|| 0,因为它需要更少的字符来输入并且还修复了一些无效值,可以将set 中的this._count = +v || 0 更改为更好的值调节。如果它是反模式,则取决于具体情况。一个对象可以扩展并且更易于测试。如果需要,它的行为可以随时更改
    【解决方案5】:

    你可以使用闭包来模拟静态变量

    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());

    【讨论】:

      【解决方案6】:

      如果你想拥有增量 ID:

       constructor() {
          super(template);
          if (typeof MyClass.nextId == 'undefined') {
          MyClass.nextId = 0;
          }
          this._id = `${MyClass.nextId++}`;
       }
      

      【讨论】:

        【解决方案7】:

        您可以使用静态 getter 和 setter 模拟静态变量

         export class MyClass {
          static get variable() {
            return this.foo;
          }
        
          static set variable(foo) {
            this.foo = foo;
          }
        }
        

        并像这样使用它

          MyClass.variable = 'bar';
          console.log(MyClass.variable);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-15
          • 2018-05-10
          • 2015-02-03
          • 1970-01-01
          相关资源
          最近更新 更多