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


86

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를 작성해야합니까?


어떤 ECMAScript 6 엔진 구현을 사용하고 있습니까?
Dai

답변:


136

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

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 컴파일러에서 작동합니다.


다른 사람을 위해 정적 접근 자 속성은 아직 Node.js에서 지원되지 않습니다. :-/ kangax.github.io/compat-table/es6/…
David Hernandez

1
최소한 Node.js 6.x +부터 이것은 지원됩니다.
NuSkooler

흐름을 사용하는 경우 unsafe.enable_getters_and_setters=true.flowconfig 아래에 줄 을 추가 해야합니다 [options](성가신).
kristina

이것은 나를 위해 작동하지 않습니다```처리되지 않은 거부 TypeError : Cannot set property dataHashKey of class Collections {api_1 | static get dataHashKey () {api_1 | return 'collections'; api_1 | }```
Pavan

54

이 문제를 해결하기 위해 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!


관련 제안은 실제로 이것 ( 정적 클래스 기능 ) 이라고 생각합니다 .
GOTO 0

29

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

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

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

11
ES6 class구문은 어쨌든 전통적인 JS 생성자 함수 및 프로토 타입의 구문 설탕 일뿐입니다.
Matt Browne 2015

인스턴스의 속성 참조를 통해 볼 수 있도록 이러한 속성을 생성자가 아닌 프로토 타입에두기를 원한다고 생각합니다.
Pointy

@Pointy OP가 참조를 위해 상수를 저장하려고한다고 추론했습니다 (거의 C # /. NET enum).
Dai

2
@MattBrowne 예, 그러나 명확한 class구문에는 약간의 미묘한 차이가 있습니다. 예를 들어로 선언 된 메서드 Class.prototype.method = function () {};열거 할 수 있지만 (for-in 루프로 표시됨) class메서드는 열거 할 수 없습니다.
Timothy Gu

4

정적 변수를 최대한 활용하기 위해이 접근 방식을 따랐습니다. 좀 더 구체적으로 말하자면, 개인 변수를 사용하거나 공용 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로 변환했습니다.


1
"완전한 이점"이란 무엇입니까? class Url { static getQueries… }; Url.staticMember = [];훨씬 간단 하지 않았을까요?
Bergi

이러한 ===비교는 모두 산출 false, btw
Bergi

"Full Advantage"는 위의 방법으로 원하는 경우 _staticMember를 비공개로 유지할 수 있음을 의미합니다.
SM Adnan 2015

-1

@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


1
static인스턴스 로 필드에 액세스하는 것은 드물지 않습니까? Java와 같은 일부 언어에서 IDE는 실제로 경고 / 힌트를 발행합니다.
Isac은

@Isac 네 맞아요. 인스턴스로 액세스하는 것은 권장되지 않으며 내 대답도 마찬가지입니다. 솔루션의 또 다른 관점입니다. 😀
legend80s
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.