Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a "public static field" in an ES6 class?

I'm making a Javascript class and I'd like to have a public static field like in Java. This is the relevant code:

export default class Agent {     CIRCLE: 1,     SQUARE: 2,     ... 

This is the error I get:

line 2, col 11, Class properties must be methods. Expected '(' but instead saw ':'. 

It looks like ES6 modules don't allow this. Is there a way to get the desired behavior or do I have to write a getter?

like image 217
aebabis Avatar asked Feb 11 '15 02:02

aebabis


People also ask

Are static fields public?

It is declared as a public field. Generally it's a bad idea to make a field public in any class you design but in this case, it doesn't matter. The value of the constant cannot be changed. The static constant is used from the class name Item, not an Item object.

What is static method in es6?

Static methods are often used to create utility functions for an application.” In other words, static methods have no access to data stored in specific objects. Note that for static methods, the this keyword references the class. You can call a static method from another static method within the same class with this.

Can fields be static?

Third, the Java field can be declared static . In Java, static fields belongs to the class, not instances of the class. Thus, all instances of any class will access the same static field variable. A non-static field value can be different for every object (instance) of a class.


2 Answers

You make "public static field" using accessor and a "static" keyword:

class Agent {     static get CIRCLE() {       return 1;     }     static get SQUARE() {       return 2;     } }  Agent.CIRCLE; // 1 

Looking at a spec, 14.5 — Class Definitions — you'd see something suspiciously relevant :)

ClassElement[Yield] :
  MethodDefinition[?Yield]
  static MethodDefinition[?Yield] ;

So from there you can follow to 14.5.14 — Runtime Semantics: ClassDefinitionEvaluation — to double check if it really does what it looks like it does. Specifically, step 20:

  1. For each ClassElement m in order from methods
    1. If IsStatic of m is false, then
      1. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments proto and false.
    2. Else,
      1. Let status be the result of performing PropertyDefinitionEvaluation for m with arguments F and false.
    3. If status is an abrupt completion, then
      1. Set the running execution context’s LexicalEnvironment to lex.
      2. Return status.

IsStatic is defined earlier in 14.5.9

ClassElement : static MethodDefinition
Return true.

So PropertyMethodDefinition is called with "F" (constructor, function object) as an argument, which in its turn creates an accessor method on that object.

This already works in at least IETP (tech preview), as well as 6to5 and Traceur compilers.

like image 78
kangax Avatar answered Oct 04 '22 06:10

kangax


Since ECMAScript 2022, you can do something like this, similar to traditional class-oriented languages like Java and C#:

class MyClass {     static myStaticProp = 42;     myProp = 42;     myProp2 = this.myProp;     myBoundFunc = () => { console.log(this.myProp); };      constructor() {         console.log(MyClass.myStaticProp); // Prints '42'         console.log(this.myProp); // Prints '42'         this.myBoundFunc(); // Prints '42'     } } 

The above is equivalent to:

class MyClass {     constructor() {         this.myProp = 42;         this.myProp2 = this.myProp;         this.myBoundFunc = () => { console.log(this.myProp); };          console.log(MyClass.myStaticProp); // Prints '42'         console.log(this.myProp); // Prints '42'         this.myBoundFunc(); // Prints '42'     } } MyClass.myStaticProp = 42; 

The features were added in the "Static Class Features" and "Class Fields" proposals by Daniel Ehrenberg et al. Google Chrome (and new Edge) started supporting both proposals in version 72, equivalent to Node.js 12+. Firefox supports public instance fields since version 69 and static instance fields since version 75. Safari supports both since version 14.1. See more info at caniuse.com.

For older browsers that don't yet support these features, you can use Babel to transpile class fields. This requires @babel/plugin-proposal-class-properties to be enabled (enabled by default in @babel/plugin-env starting from v7.14.0).


Compared to @kangax's solution of declaring a getter, this solution can also be more performant, since here the property is accessed directly instead of through calling a function.


Edit: A unified class fields proposal is now at stage 3.

Edit (February 2020): The static class features have been split out into a different proposal. Thanks @GOTO0!

Edit (March 2021): With the exception of Safari, all major browsers released after April 2020 now support this feature!

Edit (June 2021): Both proposals are accepted by TC39, the ECMAScript language committee, and Safari shipped this feature in version 14.1!

like image 42
Timothy Gu Avatar answered Oct 04 '22 07:10

Timothy Gu