Классы ES6 - Обновление статических свойств

Я пытаюсь найти альтернативные способы установить статическое (или класс) свойство класса 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

Я бы предпочел не устанавливать свойство ВНЕ определения класса, хотя. Я пробовал несколько вещей, но не могу создать статическое свойство внутри класса, которое я могу обновить из конструктора.

Я должен также упомянуть, что мне нужно сделать это в браузере (Chrome) без использования Babel или чего-либо подобного.

Вот примеры некоторых вещей, которые я пробовал:

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 "="

Ответ 1

В ES6 нет такого понятия, как static all = []. Экземпляр класса и статические поля в настоящее время являются предложениями этапа 3, которые могут быть использованы через транспортер, например, Babel. Уже существует реализация в TypeScript, которая может каким-то образом быть несовместимой с этими предложениями, но static all = [] действителен в TS и ES.Next.

Geo.all = [];

является действительным и предпочтительным способом сделать это в ES6. Альтернативой является пара геттер/сеттер - или только геттер для свойства только для чтения:

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

    return this._all;
  }

  constructor() { ... }
}

Отслеживание экземпляров в статическом свойстве обычно нельзя считать хорошим шаблоном и приведет к неконтролируемому потреблению памяти и утечкам (как было отмечено в комментариях).

Ответ 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);
      }
    }
  }

Примечание. В получателе можно также проверить наличие свойства с помощью ключевого слова in или hasOwnProperty слова 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 выдал ошибку. Поэтому я определил переменные класса "статические", а также методы получения.

Работал в 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;
  }
}