¿Declarar constantes estáticas en clases ES6?


Quiero implementar constantes en un class, porque ahí es donde tiene sentido ubicarlas en el código.

Hasta ahora, he estado implementando la siguiente solución con métodos estáticos:

class MyClass {
    static constant1() { return 33; }
    static constant2() { return 2; }
    // ...
}

Sé que existe la posibilidad de jugar con prototipos, pero muchos recomiendan no hacerlo.

¿Hay una mejor manera de implementar constantes en clases ES6?

Author: sdgluck, 0000-00-00

8 answers

Aquí hay algunas cosas que puedes hacer:

Exporta a const desde el módulo . Dependiendo de su caso de uso, solo podría:

export const constant1 = 33;

E importa eso desde el módulo cuando sea necesario. O, basándose en su idea de método estático, podría declarar un static obtener accessor :

const constant1 = 33,
      constant2 = 2;
class Example {

  static get constant1() {
    return constant1;
  }

  static get constant2() {
    return constant2;
  }
}

De esa manera, no necesitarás paréntesis:

const one = Example.constant1;

Babel REPL Example

Entonces, como usted dice, dado que un class es solo azúcar sintáctico para una función que puede simplemente añadir una propiedad no escribible como esta:

class Example {
}
Object.defineProperty(Example, 'constant1', {
    value: 33,
    writable : false,
    enumerable : true,
    configurable : false
});
Example.constant1; // 33
Example.constant1 = 15; // TypeError

Podría ser bueno si pudiéramos hacer algo como:

class Example {
    static const constant1 = 33;
}

Pero desafortunadamente esta sintaxis de propiedades de clase está solo en una propuesta ES7, e incluso entonces no permitirá agregar const a la propiedad.

 239
Author: CodingIntrigue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-18 08:51:19

Estoy usando babel y la siguiente sintaxis está funcionando para mí:

class MyClass {
    static constant1 = 33;
    static constant2 = {
       case1: 1,
       case2: 2,
    };
    // ...
}

MyClass.constant1 === 33
MyClass.constant2.case1 === 1

Tenga en cuenta que necesita el preset "stage-0".
Para instalarlo:

npm install --save-dev babel-preset-stage-0

// in .babelrc
{
    "presets": ["stage-0"]
}

Actualización:

Utilice actualmente stage-2

 16
Author: borracciaBlu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 07:31:32

En este documento dice:

No existe (intencionalmente) una forma declarativa directa de definir propiedades de clase de datos prototipo (que no sean métodos) o propiedades de instancia

Esto significa que es intencionalmente así.

Tal vez usted puede definir una variable en el constructor?

constructor(){
    this.key = value
}
 11
Author: DevAlien,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-18 11:08:34

También es posible usar Object.freeze en su objeto class(es6)/constructor function(es5) para hacerlo inmutable:

class MyConstants {}
MyConstants.staticValue = 3;
MyConstants.staticMethod = function() {
  return 4;
}
Object.freeze(MyConstants);
// after the freeze, any attempts of altering the MyConstants class will have no result
// (either trying to alter, add or delete a property)
MyConstants.staticValue === 3; // true
MyConstants.staticValue = 55; // will have no effect
MyConstants.staticValue === 3; // true

MyConstants.otherStaticValue = "other" // will have no effect
MyConstants.otherStaticValue === undefined // true

delete MyConstants.staticMethod // false
typeof(MyConstants.staticMethod) === "function" // true

Tratar de alterar la clase le dará un soft-fail (no lanzará ningún error, simplemente no tendrá ningún efecto).

 8
Author: rodrigo.botti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 19:11:03

Como https://stackoverflow.com/users/2784136/rodrigo-botti dijo, creo que estás buscando Object.freeze(). He aquí un ejemplo de una clase con estática inmutable:

class User {
  constructor(username, age) {
    if (age < User.minimumAge) {
      throw new Error('You are too young to be here!');
    }
    this.username = username;
    this.age = age;
    this.state = 'active';
  }
}

User.minimumAge = 16;
User.validStates = ['active', 'inactive', 'archived'];

deepFreeze(User);

function deepFreeze(value) {
  if (typeof value === 'object' && value !== null) {
    Object.freeze(value);
    Object.getOwnPropertyNames(value).forEach(property => {
      deepFreeze(value[property]);
    });
  }
  return value;
}
 3
Author: jeffwtribble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:29
class Whatever {
    static get MyConst() { return 10; }
}

let a = Whatever.MyConst;

Parece funcionar para mí.

 3
Author: Benny Jobigan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-10 10:30:04

Puede crear una forma de definir constantes estáticas en una clase utilizando una característica impar de las clases ES6. Dado que las estáticas son heredadas por sus subclases, puede hacer lo siguiente:

const withConsts = (map, BaseClass = Object) => {
  class ConstClass extends BaseClass { }
  Object.keys(map).forEach(key => {
    Object.defineProperty(ConstClass, key, {
      value: map[key],
      writable : false,
      enumerable : true,
      configurable : false
    });
  });
  return ConstClass;
};

class MyClass extends withConsts({ MY_CONST: 'this is defined' }) {
  foo() {
    console.log(MyClass.MY_CONST);
  }
}
 1
Author: TbWill4321,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-23 18:16:02

Aquí hay una forma más que puedes hacer

/*
one more way of declaring constants in a class,
Note - the constants have to be declared after the class is defined
*/
class Auto{
   //other methods
}
Auto.CONSTANT1 = "const1";
Auto.CONSTANT2 = "const2";

console.log(Auto.CONSTANT1)
console.log(Auto.CONSTANT2);

Nota-el Orden es importante, no puede tener las constantes anteriores

Uso consola.log (Auto.CONSTANTE 1);

 0
Author: user3871424,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-01 18:49:59