program tip

ES6 클래스에서 "공개 정적 필드"를 만들려면 어떻게합니까?

radiobox 2020. 10. 9. 10:42
반응형

ES6 클래스에서 "공개 정적 필드"를 만들려면 어떻게합니까?


Javascript 클래스를 만들고 있으며 Java와 같은 공용 정적 필드를 갖고 싶습니다. 다음은 관련 코드입니다.

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

이것은 내가 얻는 오류입니다.

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

ES6 모듈이 이것을 허용하지 않는 것 같습니다. 원하는 동작을 얻을 수있는 방법이 있습니까? 아니면 getter를 작성해야합니까?


접근 자와 "정적"키워드를 사용하여 "공개 정적 필드"를 만듭니다.

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

Agent.CIRCLE; // 1

사양을 보면 14.5 — 클래스 정의 — 의심 스러울 정도로 관련성이있는 것을 볼 수 있습니다. :)

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

그래서 거기에서 14.5.14 — Runtime Semantics : ClassDefinitionEvaluation —을 따라 가면 그것이 실제로하는 것처럼 보이는지 다시 한 번 확인할 수 있습니다. 특히 20 단계 :

  1. 메서드에서 순서대로 각 ClassElement m에 대해
    1. 경우 m의 IsStatic은 false입니다 다음,
      1. 상태를 proto 및 false 인수를 사용하여 m에 대해 PropertyDefinitionEvaluation을 수행 한 결과라고합시다.
    2. 그밖에,
      1. status를 인수 F 및 false를 사용하여 m에 대해 PropertyDefinitionEvaluation을 수행 한 결과라고합시다.
    3. 상태가 갑작스런 완료 인 경우
      1. 실행중인 실행 컨텍스트의 LexicalEnvironment를 lex로 설정합니다.
      2. 반환 상태.

IsStatic은 14.5.9 이전에 정의되었습니다.

ClassElement : static MethodDefinition
true 반환합니다.

따라서 PropertyMethodDefinition"F"(생성자, 함수 객체)를 인수로 사용하여 호출되며, 그러면 해당 객체에 대한 접근 자 메서드생성 됩니다.

이것은 적어도 IETP (기술 미리보기)와 6to5 및 Traceur 컴파일러에서 이미 작동합니다 .


이 문제를 해결하기 위해 Daniel Ehrenberg와 Jeff Morrison이 작성한 "Class Fields" 라는 3 단계 ECMAScript 제안 이 있습니다.

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

위의 내용은 다음과 같습니다.

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 @ babel / plugin-proposal-class-properties ( 3 단계 사전 설정에 포함됨)를 통해 클래스 필드 변환을 지원 하므로 JavaScript 런타임에서 지원하지 않는 경우에도이 기능을 사용할 수 있습니다.


@kangax의 getter 선언 솔루션과 비교할 때이 솔루션은 함수를 호출하는 대신 직접 속성에 액세스하기 때문에 더 성능이 좋습니다.

이 제안이 받아 들여지면 자바 및 C♯와 같은 전통적인 객체 지향 언어와 유사한 방식으로 자바 스크립트 코드를 작성할 수 있습니다.


편집 : 통합 된 클래스 필드 제안이 이제 3 단계에 있습니다. Babel v7.x 패키지로 업데이트합니다.


현재 ECMAScript 6 초안 (2015 년 2 월 현재)에서 모든 클래스 속성은 값이 아니라 메서드 여야합니다 (ECMAScript에서 "속성"은 개념 상 OOP 필드와 유사하지만 필드 값은 Function객체 여야하며 a Number또는 Object) 와 같은 다른 값 .

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

 class Agent {
 }
 Agent.CIRCLE = 1;
 Agent.SQUARE = 2;
 ...

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


@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

참고URL : https://stackoverflow.com/questions/28445693/how-do-i-make-a-public-static-field-in-an-es6-class

반응형