【问题标题】:ES6 Classes - Updating Static PropertiesES6 类 - 更新静态属性
【发布时间】:2017-10-20 19:56:00
【问题描述】:

我正在尝试找出替代方法来将静态(或类)属性设置为 ES6 类,然后在创建类的新实例后更改它。

例如,假设我有一个名为Geo 的类,我需要一个名为all 的静态属性,它将为我提供Geo 类的所有实例的数组。

此版本有效:

class Geo {
  constructor(name){
    this.name = name;
    Geo.all.push(this);
  }
}

Geo.all = [];

ruby = new Geo("Ruby");
rocks = new Geo("Rocks");
console.log(Geo.all.length); // => 2

我宁愿不要在类定义之外设置属性。我已经尝试了一些东西,但似乎无法在类中创建可以从构造函数更新的静态属性。

我还应该提到我需要能够在不使用 Babel 或类似工具的情况下在浏览器 (Chrome) 中执行此操作。

以下是我尝试过的一些示例:

class Geo {
  constructor(name){
    this.name = name;
    Geo.all.push(this);
  }
  static get all() {
    return [];
  }
}

ruby = new Geo("Ruby");
rocks = new Geo("Rocks");
console.log(Geo.all.length); // => 0 

还有一个

class Geo {
  constructor(name){
    this.name = name;
    Geo.all.push(this);
  }

  static all = [];
}

ruby = new Geo("Ruby");
rocks = new Geo("Rocks");
console.log(Geo.all.length); // => error unexpected "="

【问题讨论】:

  • 在 ES6 中没有其他方法可以做到这一点。
  • Geo.all = [] 有什么问题?
  • 你不应该有一个全局的实例集合——这会导致内存泄漏和模块化(例如可测试性)问题
  • 您可以在构造函数中执行Geo.all = (Geo.all || []).concat(this);。然而,类定义之外的静态初始化程序是解决此问题的“惯用”标准方法。它还保证Geo.all 的存在,甚至在创建第一个实例之前。
  • 如果您想跟踪特定对象的所有实例,那么您可能不想将它们放入数组中,因为这可能会导致内存泄漏,因为这样做会迫使您的代码管理每个对象的内存(您必须手动将其从数组中删除,以便垃圾收集器释放它,这会扼杀垃圾收集的很多用处)。您可以将它们放在 weakMap 或 weakSet 中,具体取决于您希望如何访问它们并且不会杀死垃圾收集。

标签: javascript class oop object ecmascript-6


【解决方案1】:

ES6 中没有 static all = [] 这样的东西。 instance 和 static 类字段目前是第 3 阶段提案,可以通过转译器使用,例如通天塔。 TypeScript 中已有的实现可能在某种程度上与这些提议不兼容,但 static all = [] 在 TS 和 ES.Next 中有效。

Geo.all = [];

是在 ES6 中执行此操作的有效且可取的方式。另一种方法是 getter/setter 对 - 或者只是只读属性的 getter:

class Geo {
  static get all() {
    if (!this._all)
      this._all = [];

    return this._all;
  }

  constructor() { ... }
}

在静态属性中跟踪实例通常不能被认为是一种好的模式,并且会导致无法控制的内存消耗和泄漏(正如在 cmets 中提到的那样)。

【讨论】:

【解决方案2】:

这对我来说适用于静态属性。

  class NeoGeo {

    constructor() {

    }

    static get topScore () {
      if (NeoGeo._topScore===undefined) {
        NeoGeo._topScore = 0; // set default here
      }

      return NeoGeo._topScore;
    }

    static set topScore (value) {
      NeoGeo._topScore = value;
    }

  }

还有你的例子:

  class NeoGeo {

    constructor() {
      NeoGeo.addInstance(this);
      console.log("instance count:" + NeoGeo.all.length);
    }

    static get all () {

      if (NeoGeo._all===undefined) {
        NeoGeo._all = [];
      }

      return NeoGeo._all;
    }

    static set all (value) {
      NeoGeo._all = value;
    }

    static addInstance(instance) {
      // add only if not already added
      if (NeoGeo.all.indexOf(instance)==-1) {
        NeoGeo.all.push(instance);
      }
    }
  }

注意:在 getter 中,您还可以使用 in 关键字或 hasOwnProperty 关键字检查属性是否存在。

    static get topScore () {
      if (!("_topScore" in NeoGeo)) {
        NeoGeo._topScore = 0; // set default here
      }

      return NeoGeo._topScore;
    }

并使用hasOwnProperty:

    static get topScore () {
      if (NeoGeo.hasOwnProperty("_topScore")==false) {
        NeoGeo._topScore = 0; // set default here
      }

      return NeoGeo._topScore;
    }

【讨论】:

    【解决方案3】:

    我最近遇到了创建静态类的类似问题。

    我首先尝试使用常量类变量,但 Chrome 调试器抛出错误。 所以我定义了类变量“静态”,还有 getter 方法。

    在 Chrome 中工作。

    class TestClass {
      //static properties.
      static _prop1 = [ 'A', 'B', 'C'];
      static _prop2 = true;
      static _prop3 = 'some String';
      
      //constructor. Commented out because the class only has static elements.
      //constructor () {}
      
      //Getters.
      static get prop1 () {
        return this._prop1;
      }
      
      static get prop2 () {
        return this._prop2;
      }
      
      static get prop3 () {
        return this._prop3;
      }
    }

    【讨论】:

      【解决方案4】:

      正确添加 getter 的唯一方法是扩展类并使用该扩展类。

      class Basic {
        get firstGetter() {
          return 'firstGetter'
        }
      }
      class ExtendedClass extends Basic {
        get firstGetter() {
          return 'updatedFirstGetter'
        }
      }

      }

      【讨论】:

        【解决方案5】:

        将您的节点更新到版本 12 或更高版本,就是这样 ;)

        【讨论】:

        猜你喜欢
        • 2017-06-07
        • 2016-11-16
        • 2016-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 2018-06-09
        • 1970-01-01
        相关资源
        最近更新 更多