Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ES6 Classes - Updating Static Properties

I am trying to figure out alternative ways to set a static (or class) property an ES6 Class and then change it after new instances of the class are created.

For example, lets say I have a class called Geo, and I need a static property called all that will give me the array of all instances of the Geo class.

This version works:

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

I would prefer to not set the property OUTSIDE of the class definition though. I've tried a few things but can't seem to create a static property within the class that I can update from the constructor.

I should also mention I need to be able to do this in the browser (Chrome) without use of Babel or similar.

Here are examples of some things I've tried:

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 

And another

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 "="
like image 752
Jared Avatar asked May 20 '17 21:05

Jared


2 Answers

There's no such thing as static all = [] in ES6. Class instance and static fields are currently stage 3 proposals which can be used via a transpiler, e.g. Babel. There's already existing implementation in TypeScript that may be incompatible with these proposals in some way, yet static all = [] is valid in TS and ES.Next.

Geo.all = [];

is valid and preferable way to do this in ES6. The alternative is getter/setter pair - or only a getter for read-only property:

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

    return this._all;
  }

  constructor() { ... }
}

Tracking instances in static property can't generally be considered a good pattern and will lead to uncontrollable memory consumption and leaks (as it was mentioned in comments).

like image 184
Estus Flask Avatar answered Sep 30 '22 04:09

Estus Flask


This works for me for static properties.

  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;
    }

  }

And your example:

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

Note: In the getter you could also check for the existence of the property using the in keyword or the hasOwnProperty keyword.

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

      return NeoGeo._topScore;
    }

And using hasOwnProperty:

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

      return NeoGeo._topScore;
    }
like image 28
1.21 gigawatts Avatar answered Sep 30 '22 06:09

1.21 gigawatts