[javascript] 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이 작성한 “Static Class Features” 라는 3 단계 ECMAScript 제안 이 있습니다. 3 단계 “클래스 필드” 제안 과 함께 향후 코드는 다음과 같습니다.

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 패키지로 업데이트합니다.

편집 (2020 년 2 월) : 정적 클래스 기능이 다른 제안으로 분할되었습니다. 감사합니다 @ GOTO0!


답변

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

기존 ECMAScript 생성자 속성 지정자를 사용하여 계속 지정할 수 있습니다.

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


답변

정적 변수를 최대한 활용하기 위해이 접근 방식을 따랐습니다. 좀 더 구체적으로 말하자면, 개인 변수를 사용하거나 공용 getter 만 있거나 getter 또는 setter를 모두 갖는 데 사용할 수 있습니다. 마지막 경우에는 위에 게시 된 솔루션 중 하나와 동일합니다.

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'];

Url을 확장하는 다른 클래스를 만들 수 있었고 작동했습니다.

바벨을 사용하여 ES6 코드를 ES5로 변환했습니다.


답변

@kangax의 대답은 기존 OOP 언어의 전체 정적 동작을 모방하지 않습니다. const agent = new Agent; agent.CIRCLE; // Undefined

OOP와 같은 정적 속성에 액세스하려면 다음은 내 솔루션입니다.

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

NewApp.MULTIPLE_VERSIONS_SUPPORTED = true;

다음과 같이 코드를 테스트하십시오.

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


답변