How to create a “public static field” in ES6 class?

I am creating a Javascript class, and I would like to have a public static field, as in Java. This is the corresponding 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 seems that ES6 modules do not allow this. Is there a way to get the desired behavior or do I need to write getter?

+45
javascript ecmascript-6
Feb 11 '15 at 2:42
source share
5 answers

You create a “public static field” using an accessor and a “static” keyword:

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

Looking at the spec, 14.5 - Class definitions - you will see something suspiciously relevant :)

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

So, from there you can go to 14.5.14 - Run -time semantics: ClassDefinitionEvaluation - double-check to see if it really does what it looks like. In particular, step 20:

  • For each class Class m in order of methods
    • If IsStatic of m is false , then
      • Let status be the result of executing PropertyDefinitionEvaluation for m with arguments proto and false.
    • Otherwise,
      • Let status be the result of executing a PropertyDefinitionEvaluation for m with arguments F and false.
    • If the state is abrupt termination, then
      • Define LexicalEnvironment runtime execution contexts for lex.
      • Return Status.

IsStatic defined earlier in 14.5.9

ClassElement: static MethodDefinition
True true.

So, PropertyMethodDefinition is called using "F" (constructor, function object) as an argument, which, in turn, creates a method for accessing this object .

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

+72
Feb 11 '15 at 12:21
source share

There is an ECMAScript Stage 3 proposal called Class Fields by Daniel Ehrenberg and Jeff Morrison, whose goal is to solve this problem.

 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; 

Babel supports passing class fields via @ babel / plugin-proposal-class-properties (included in pre-launch-3 ) so you can use this function even if your JavaScript runtime does not support it.




Compared to the @kangax getter declaration solution, this solution can also be more efficient, since here the resource is accessed directly, and not through a function call.

If this proposal is accepted, then it will be possible to write JavaScript code in a way that is more like traditional object-oriented languages ​​such as Java and C♯.




Edit: the class offer of unified classes is now at stage 3; upgrade your Babel v7.x packages.

+24
Aug 02 '16 at 18:18
source share

In current ECMAScript 6 projects (as of February 2015), all class properties should be methods and not values ​​(a note in ECMAScript “Property” is similar to the definition for an OOP field, except that the field value must be Function , not any other value, such as Number or Object ).

You can still specify them using the traditional property specifiers of the ECMAScript constructor:

  class Agent { } Agent.CIRCLE = 1; Agent.SQUARE = 2; ... 
+21
Feb 11 '15 at 2:53
source share

To take full advantage of the static variable, I followed this approach. To be more specific, we can use it to use a private variable or to have only an open getter or to have both getter and setter. In the latter case, this is the same as one of the solutions published above.

 var Url = (() => { let _staticMember = []; return class { static getQueries(hash = document.location.hash) { return hash; } static get staticMember(){ return _staticMember; } }; })(); Usages: console.log(Url.staticMember); // []; Url.staticMember.push('it works'); console.log(Url.staticMember); // ['it works']; 

I could create another class extending Url and it worked.

I used babel to convert my ES6 code to ES5

+2
Jul 06 '15 at 0:05
source share

@ Kangax's answer does not imitate the entire static behavior of traditional OOP languages, because you cannot access the static property through an instance of the const agent = new Agent; agent.CIRCLE; // Undefined const agent = new Agent; agent.CIRCLE; // Undefined

If you want to access a static property, just like OOP, here is my solution:

 class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; // Late binding for inheritance } } NewApp.MULTIPLE_VERSIONS_SUPPORTED = true; 

Check the code as follows.

 class NewApp { get MULTIPLE_VERSIONS_SUPPORTED() { console.log('this.constructor.name:', this.constructor.name); // late binding return this.constructor.MULTIPLE_VERSIONS_SUPPORTED; } } // Static property can be accessed by class NewApp.MULTIPLE_VERSIONS_SUPPORTED = true; const newApp = new NewApp; // Static property can be accessed by it instances console.log('newApp.MULTIPLE_VERSIONS_SUPPORTED:', newApp.MULTIPLE_VERSIONS_SUPPORTED); // true // Inheritance class StandardApp extends NewApp {} // Static property can be inherited console.log('StandardApp.MULTIPLE_VERSIONS_SUPPORTED:', StandardApp.MULTIPLE_VERSIONS_SUPPORTED); // true // Static property can be overwritten StandardApp.MULTIPLE_VERSIONS_SUPPORTED = false; const std = new StandardApp; console.log('std.MULTIPLE_VERSIONS_SUPPORTED:', std.MULTIPLE_VERSIONS_SUPPORTED); // false 
+1
Mar 17 '17 at 9:04 on
source share



All Articles