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

后端 未结 5 2011
滥情空心
滥情空心 2020-11-27 14:13

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:          


        
相关标签:
5条回答
  • 2020-11-27 15:01

    To get full advantage of static variable I followed this approach. To be more specific, we can use it to use private variable or having only public getter, or having both getter or setter. In the last case it's same as one of the solution posted 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

    0 讨论(0)
  • 2020-11-27 15:07

    @kangax 's answer does not imitate the whole static behaviour of traditional OOP language's, because you cannot access the static property by it's instance like const agent = new Agent; agent.CIRCLE; // Undefined

    If you want to access static property just like OOP's, 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;
    

    Test 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's 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

    0 讨论(0)
  • 2020-11-27 15:12

    In current drafts of ECMAScript 6 (as of February 2015), all class properties must be methods, not values (note in ECMAScript a "property" is similar in concept to an OOP field, except the field value must be a Function object, not any other value such as a Number or Object).

    You can still specify these using traditional ECMAScript constructor property specifiers:

     class Agent {
     }
     Agent.CIRCLE = 1;
     Agent.SQUARE = 2;
     ...
    
    0 讨论(0)
  • 2020-11-27 15:13

    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.

    0 讨论(0)
  • 2020-11-27 15:15

    There is a Stage 3 ECMAScript proposal called "Static Class Features" by Daniel Ehrenberg and Jeff Morrison that aims to solve this problem. Along with the Stage 3 "Class Fields" proposal, future code will look like this:

    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 transpiling class fields through @babel/plugin-proposal-class-properties (included in the stage-3 preset), so that you can use this feature even if your JavaScript runtime doesn't support it.


    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.

    If this proposal gets accepted, then it will be possible to write JavaScript code in a way that's more similar to traditional object-oriented languages like Java and C♯.


    Edit: A unified class fields proposal is now at stage 3; update to Babel v7.x packages.

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

    0 讨论(0)
提交回复
热议问题