JavaScript (ECMAScript) 데코레이터 및 객체의 속성 설명자에 대한 최소 가이드

기본 예제와 ECMAScript 에코 시스템에 대한 약간의 정보가 포함 된 ECMAScript "장식 자"제안에 대한 간략한 소개입니다.

⚠️ 이 기사는 ECMAScript 데코레이터 제안 변경으로 인해 최근 에 수정 되었습니다 . 여기 에서이 기사 의 이전 버전을 읽을 수 있습니다 .

제목 에 JavaScript 데코레이터 대신 ECMAScript 데코레이터가있는 이유는 무엇 입니까? ECMAScriptJavaScript 와 같은 스크립팅 언어를 작성하기위한 표준 이기 때문 입니다. 모든 사양을 지원하기 위해 JavaScript를 시행하지는 않지만 JavaScript 엔진 ( 브라우저 내에서 구현 됨 )은 ECMAScript에 도입 된 기능 또는 약간 다른 동작으로 지원을 지원하거나 지원하지 않을 수 있습니다.

ECMAScript를 영어 와 같이 사용 하는 언어 로 고려하십시오 . 그렇다면 JavaScript는 영국 영어 와 같은 방언 이 될 것 입니다. 방언은 그 자체로 언어이지만 파생 된 언어의 원칙을 기반으로합니다. 따라서 ECMAScript는 JavaScript 요리 / 작성을위한 요리 책이며 모든 재료 / 규칙을 따르는 지 여부는 요리사 / 개발자에게 달려 있습니다.

일반적으로 JavaScript 채택 자 ( 예 : 웹 브라우저 또는 Node.js와 같은 서버 측 플랫폼 )는 언어로 작성된 모든 사양을 구현하고 ( 그렇지 않으면 표준이 무너지는 요점 ) 일반적으로 베타 미리보기 버전과 함께 제공합니다. 구현이 안정적인지 확인하십시오.

ECMA International의 TC39 또는 Technical Committee 39 는 ECMAScript 표준을 유지 관리 할 책임이 있습니다. 이 팀의 구성원은 ECMA International, 브라우저 공급 업체 및 Google, Mozilla 등과 같은 웹 산업 전반에 관심이있는 회사에 속합니다.

ECMAScript는 개방형 표준이므로 누구나 언어에 큰 도움이 될 새로운 아이디어 나 기능을 제안 할 수 있습니다. 따라서 새로운 기능에 대한 제안은 4 개의 주요 단계를 거쳐 해당 기능이 승인되고 표준에 포함될 때까지 TC39가이 프로세스에 참여합니다.

+-------+-----------+----------------------------------------+
| stage | name      | mission                                |
+-------+-----------+----------------------------------------+
| 0     | strawman  | Present a new feature (proposal)       |
|       |           | to TC39 committee. Generally presented |
|       |           | by TC39 member or TC39 contributor.    |
+-------+-----------+----------------------------------------+
| 1     | proposal  | Define use cases for the proposal,     |
|       |           | dependencies, challenges, demos,       |
|       |           | polyfills etc. A champion              |
|       |           | (TC39 member) will be                  |
|       |           | responsible for this proposal.         |
+-------+-----------+----------------------------------------+
| 2     | draft     | This is the initial version of         |
|       |           | the feature that will be               |
|       |           | eventually added. Hence description    |
|       |           | and syntax of feature should           |
|       |           | be presented. A transpiler such as     |
|       |           | Babel should support and               |
|       |           | demonstrate implementation.            |
+-------+-----------+----------------------------------------+
| 3     | candidate | Proposal is almost ready and some      |
|       |           | changes can be made in response to     |
|       |           | critical issues raised by adopters     |
|       |           |  and TC39 committee.                   |
+-------+-----------+----------------------------------------+
| 4     | finished  | The proposal is ready to be            |
|       |           | included in the standard.              |
+-------+-----------+----------------------------------------+

지금부터 우리는 JavaScript 엔진에서 여전히 실험적인 것으로 간주되는 JavaScript 기능을 작업 중이므로 Node.js 버전이이를 지원하지 않을 수 있습니다. 따라서 데코레이터 구문을 바닐라 JavaScript 구문으로 변환 하려면 Babel 또는 TypeScript 트랜스 파일러 가 필요 합니다. 사용 JS-플러그인 스타트 아주 기본적인 프로젝트를 설정하는 플러그인을. 이 문서에서 다룰 내용과 잘 작동하도록이 상용구를 구성했습니다.

데코레이터를 이해하려면 먼저 JavaScript 객체 속성 의 속성 설명자가 무엇인지 이해해야 합니다. 속성 디스크립터 속성인지 같은 객체 속성에 규칙 세트이며, 쓰기 또는 열거 . 자세한 내용은 아래 강의를 따르십시오.

✱ 클래스 메서드 데코레이터

이제 객체의 새 속성이나 기존 속성을 정의하고 구성하는 방법을 이해 했으므로 이제 데코레이터와 속성 설명자에 대해 논의한 이유를 살펴 보겠습니다.

장식은 자바 스크립트 함수입니다 ( 순수 기능을 권장 클래스 속성 / 메소드 나 클래스 자체를 수정하는 데 사용됩니다). 클래스 속성 , 메서드 또는 클래스 자체 @decoratorFunction의 맨 위에 구문 을 추가하면 클래스 또는 클래스 속성을 수정하는 데 사용할 수있는 인수가 거의없이 호출 됩니다 .decoratorFunction

데코레이터가 여전히 ECMAScript 제안 프로세스의 2 단계에 있기 때문에이 기능이 JavaScript 엔진 내부에서 구현되지 않았기 때문에 브라우저 또는 노드 내부에 데코레이터가 포함 된 JavaScript 코드를 실행할 수 없습니다. 이를 위해서는 데코레이터가 포함 된 JavaScript 코드를 JavaScript 엔진이 이해할 수있는 다른 것으로 컴파일 할 수있는 Babel 또는 TypeScript 와 같은 트랜스 파일러 를 사용해야합니다 .

우리는 단순성 을 위해 Babel 을 사용할 것 입니다. 이 문서 에 따라 프로젝트 내에 Babel 및 CLI를 설치할 수 있습니다 .

$ npm install --save-dev @babel/core @babel/cli
$ npx babel --version
7.10.4 (@babel/core 7.10.4)

$ npm install --save-dev @babel/preset-env
$ npm install --save-dev @babel/plugin-proposal-decorators

사전 설정은 파일과 같은 구성 파일 내에 나열된 설정을 사용하여 컴파일 프로세스를 구성하고 수행.babelrc 합니다. ES6 이상의 @babel/preset-env기능을 포함하는 표준 JavaScript 코드 를 ES5 이하로 변환하는 플러그인 이 포함되어 있습니다 .

제안서가이 예의 데코레이터와 같은 초기 단계에있는 경우 미리 설정에 포함되지 않을 수 있습니다 . 따라서 플러그인을 별도로 설치해야합니다 . 따라서 @babel/plugin-proposal-decorators데코레이터를 컴파일하기 위해 플러그인을 별도로 설치했습니다 .

이제 Babel CLI에 @babel/preset-env사전 설정과 @babel/plugin-proposal-decorators플러그인 을 사용하도록 지시해야합니다 . babel.config.json프로젝트 디렉토리에를 생성 해 보겠습니다 . 여기 에서이 파일 더 읽을 수 있습니다 .

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        [
            "@babel/plugin-proposal-decorators",
            {
                "decoratorsBeforeExport": true
            }
        ]
    ]
}
(babel-test.js)

간단한 readonly데코레이터를 만들어 봅시다 . 하지만 그 전에, 간단하게 만들 수 User와 클래스 getFullName결합하여 사용자의 전체 이름을 반환 방법 firstName등을 lastName.

(user-class.js)

위의 코드 John Doe는 콘솔에 인쇄 됩니다. 그러나 큰 문제가 있습니다 getFullName. 누구나 방법 을 수정할 수 있습니다 .

(user-class-hacked.js)

메서드를 재정의하기위한 공개 액세스를 방지하려면 객체 에있는 getFullName메서드의 속성 설명자를 수정해야 User.prototype합니다. 클래스 메소드는 단지이다 특성기능 일들은 객체 속성에 꽤 비슷하므로 값.

(user-class-readonly.js)

이제 해커가 getFullName메서드 를 재정의하려고 하면 재정의 작업이 무시됩니다. 에서 엄격 모드 우리는 앞의 예에서 본 바와 같이,이 작업은 오류가 발생합니다.

그러나 User클래스에 메서드가 많으면 수동으로 수행하는 것이 그렇게 좋지 않습니다. 이것이 데코레이터가 들어오는 곳입니다. 아래와 같이 메소드 @readonly위에 어노테이션을 추가 하여 동일한 결과를 얻을 수 getFullName있습니다.

(user-readonly-decorator.js)

한 번 봐 가지고 readonlyfuction를합니다. 데코레이터는 JavaScript 런타임이 데코레이터를 만날 때 호출되는 함수에 불과합니다. target이 함수 의 인수 값은 데코레이터가 추가 된 엔티티의 객체 표현이며이 getFullName경우 메서드입니다.

target객체가 호출됩니다 요소 에 따라 ECMAScript를 제안 하지만 우리는 그것을 호출하려고하는 대상 그것의 지옥을 위해. 이 target개체에는 수정중인 요소에 대한 설명 이 포함되어 있습니다. 클래스 메서드 ( prototype property ), 클래스 필드 ( instance field ) 또는 클래스 자체 일 수 있습니다.

target개체는 다음과 같습니다.

{
  kind: 'method' | 'accessor' | 'field' | 'class',
  key: '<property-name>',
  descriptor: <property-descriptor>,
  placement: 'prototype' | 'static' | 'own',
  initializer: <function>,
  ...
}

getFullName메서드를 꾸미기 때문에 메서드 descriptor의 속성 설명자를 가리 킵니다 getFullName. 클래스의 메서드는 프로토 타입에 있으며 프로토 타입은 객체입니다. 따라서 클래스의 메서드는 프로토 타입의 속성이고 그 값은 함수입니다.

데코레이터 함수 내 target에서 어떤 희생을 치르더라도 객체 를 반환해야 합니다. 하지만 그 전에 descriptor타겟의 변경이 가능합니다 . 이는 descriptor해당 속성의 기존 속성 설명자를 대체합니다. 위의 예에서는 로 설정 하여 getFullName( method ) 속성을 읽기 전용으로 설정 descriptor.writable했습니다 false.

하지만이 프로그램을으로 실행하려고했을 때 nodeNode.js는 @readonly구문을 인식하지 못합니다 . 이것이 우리가 Babel을 설정 한 이유입니다. babel을 사용하여이 프로그램을 컴파일 한 다음 Node.js를 사용하여 실행 해 보겠습니다.

(user-readonly-decorator.js)

이제 Babel로 코드를 컴파일하고 Node로 출력 파일을 실행하면 런타임에서 getFillName속성이 읽기 전용이므로 작성할 수 없다는 예상 오류가 발생 합니다.

(user-readonly-decorator-target.js)

위의 예에서 우리는 대상 객체 데코레이터가 꾸미고 있다는 것을 기록했습니다. 보시다시피 kindis methodkeyis getFullName메서드 이름입니다. 배치는 prototpe클래스의 프로토 타입에 있고 디스크립터에는 value다른 기능 이 포함되어 있기 때문 입니다.

와 같은 데코레이터 주석의 또 다른 버전이 있습니다 @decorator( ...args ). args장식에 전달 된 사용자 지정 인수는 다음과 같습니다 . 이것은 데코레이터 호출 이기 때문에 데코레이터 함수는 타겟을 데코 레이팅 하는 함수반환 해야합니다 . 이 함수 호출은 실제 데코레이터를 반환하기 때문에 데코레이터 팩토리 라고도합니다 .

(user-readonly-decorator-func.js)

클래스 메서드가 static인 경우 메서드는 prototype. User클래스에 정적 메서드를 추가해 보겠습니다 .

(class-static-method.js)

위의 예에서 User클래스에는 getVersion메서드가 있지만 속성 설명자가 기본적 writable으로 true로 설정되므로 침입자가이를 재정의 할 수 있습니다. 똑같은 오래된 @readonly데코레이터를 만들어 봅시다 .

(class-static-decorator.js)

target객체가 메서드 자체를 가리 키기 때문에 인스턴스 메서드와 정적 메서드간에 변경된 사항이 없습니다. target객체 의 유일한 변경 사항은 정적 메서드이기 때문에 placement그렇지 않은 static것입니다.

✱ 클래스 인스턴스 속성 데코레이터

지금까지 @decorator또는 @decorator(..args)구문 을 사용하여 메서드의 속성 설명자를 변경하는 것을 보았습니다 . 그러나 공용 / 개인 속성 ( 클래스 인스턴스 필드 )은 어떻습니까?

// user.java
class User {
  String firstName = "John"; // class property
  String lastName = "Doe"; // class property
User(String firstName, String lastName){
    this.firstName = lastName;
    this.firstName = lastName;
  }
}

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        [
            "@babel/plugin-proposal-decorators",
            {
                "decoratorsBeforeExport": true
            }
        ],
        [
            "@babel/plugin-proposal-class-properties",
            {
                "loose": true
            }
        ]
    ]
}

간단한 User클래스를 정의 해 보겠습니다. 이번에 는 생성자 내에서 firstNamelastName인스턴스 속성에 대한 기본값을 설정할 필요가 없습니다 . 수업 수준 자체에서 할 수 있습니다.

(class-default-properties.js)

당신이 선택하면 지금 prototypeUser클래스, 당신은 볼 수 없습니다 firstNamelastName특성. 그러나 getFullName메서드는 클래스 속성으로 정의되었으므로 인스턴스의 속성이되었습니다.

클래스 인스턴스 필드OOP (Object-Oriented Programming ) 에서 매우 유용하고 중요한 부분입니다 . constructor클래스 에서 함수를 완전히 제거 할 수 있으며 기본값을 사용하여 인스턴스에 이러한 속성을 계속 유지할 수 있습니다 .

그러나주의 사항이 있습니다. 클래스 프로토 타입에있는 클래스 메서드 나 클래스 자체에있는 정적 메서드와 달리 클래스 속성은 인스턴스에 있습니다. 즉, 클래스 속성을 장식하려면 인스턴스가 생성되는 동안 그렇게해야합니다.

즉, 이전 예제를 수정하고 @upperCase클래스 인스턴스 속성 기본값의 대소 문자를 변경 하는 간단한 데코레이터를 만들어 보겠습니다 .

(default-property-decorator.js)

클래스 속성을 장식하는 동안 상황이 조금 이상하게 보일 수 있습니다. 이번에 는 클래스 의 인스턴스가 생성 될 때 호출되는 함수 인 객체 intializer에 대한 속성 targetUser있습니다. 이 함수는 속성의 초기 값을 반환합니다.

속성의 사용자 지정 이니셜 라이저를 작성하는 새 함수를 할당하여이 함수를 재정의 할 수 있습니다. 이 함수를 호출하고 원래 초기 값을 검색 할 수 있습니다. 우리는 또한 descriptor평소와 같이 대상에 속성 의 개체를 가지고 있으므로 그것도 엉망으로 만들 수 있습니다.

이 제안은 또한 클래스에 대한 정적 속성 지원을 제공합니다. 아래 예에서는 모든 클래스 속성을 정적으로 만들었습니다.

(default-static-property-decorator.js)

정적 속성은 클래스에 있기 때문에 일반 정적 메서드 양식을 사용하여 정의 된 정적 메서드와 정적 클래스 속성 양식 ( ) 간에 차이가 없으므로이 메서드 this내부에서 User클래스를 가리 킵니다 . 그러나 target객체는 descriptor.value이전 접근 방식과 initializer이후 접근 방식에 있습니다.

✱ 클래스 데코레이터

이제 우리는 데코레이터가 할 수있는 일에 익숙해졌습니다. 클래스 메서드와 클래스 필드 ( static 및 instance ) 의 속성과 동작을 변경하여 클래스 동작을 동적으로 변경할 수있는 유연성을 제공합니다.

데코레이터는 수업을 꾸밀 수도 있습니다. 예를 들어 클래스 내부에 메서드를 동적으로 추가하려면 데코레이터를 사용하면됩니다.

(class-dynamic-method.js)

위의 예제에서는 클래스 정의 후 프로토 타입 메서드 뿐만 아니라 클래스 getVersion에 정적 메서드를 추가했습니다 . 데코레이터를 사용하여 동일한 결과를 얻을 수 있습니다. 하지만 먼저 클래스 요소 의 값을 확인하겠습니다 .UsergetFullNametarget

(class-peek-target.js)

target수업을 꾸미는 동안 의 물건은 조금 다르게 보입니다. 이제 target객체는 kind클래스 elements의 잠재적 대상 (요소) 일 뿐인 클래스와 속성을 갖습니다. 현재 getVersion정적 메서드에 대한 요소가 있습니다.

우리가 원하는 것은 elements어레이에 새로운 타겟을 밀어 넣는 것 입니다. element프로토 타입 메서드를 설명하는를 추가해 보겠습니다 .

(class-decorator.js)

위의 예에서 add함수를 받아서 클래스의 프로토 타입에 추가하는 데코레이터를 만들었습니다 . 프로토 타입 메서드를 설명하는 요소를 elements클래스 배열 에 수동으로 추가하여이를 달성했습니다 .

데코레이터는 훌륭합니다. 여러 데코레이터를 서로 위에 배치하여 함께 연결할 수 있습니다 . 실행 순서는 출현 순서와 동일합니다.

데코레이터는 작업을 더 빠르게 수행 할 수있는 멋진 방법입니다. 그러나 ECMAScript 사양에 추가 될 때까지 구현을 시작하기 전에 잠시 기다려야 할 수도 있습니다.

(thatisuday.com / GitHub / Twitter / StackOverflow / Instagram)

Suggested posts

JavaScript 테스트의 기초

JavaScript 테스트의 기초

"잠깐만 요, JavaScript 테스팅에 대한 또 다른 기사"라고 생각할 수 있습니다. 예, JavaScript 테스트의 기본 사항에 대해 더 많이 이야기하고 싶은 이유는이 주제에 대한 많은 기사가 JavaScript 테스트를 작성하기위한 코드 스 니펫과 도구를 보여줌으로써 매우 유사한 방식으로 작성 되었기 때문입니다.

Big-O 렌즈를 통한 Javascript의 배열 및 객체 성능

Big-O 렌즈를 통한 Javascript의 배열 및 객체 성능

프로그램의 효율성은 요소의 검색, 정렬, 액세스, 삽입 및 제거와 같은 작업을 수행하기 위해 엄청난 양의 데이터를 처리 할 때 시간 복잡성에 직접적으로 의존합니다. 성능 향상의 필요성에 따라 객체와 배열을 선택적으로 사용할 수 있습니다.

Related posts

성능 최적화 된 A / B 테스트 솔루션

성능 최적화 된 A / B 테스트 솔루션

의제 : 소개 : TL;하지만 읽을 수 있습니다. A / B 테스트, CloudFront 및 Lamba @ edge에 대해 이미 알고있는 경우 AWS Lambda @ edge를 사용한 A / B 테스트로 직접 이동하십시오. A / B 테스트 란 무엇입니까? A / B 테스트는 웹 사이트의 두 가지 버전에 대한 사용자의 참여를 비교하는 데 초점을 맞춘 UX 연구 방법론입니다.

fp-ts (Typescript)에서 Option 및 둘 중 하나 사용

저는 함수형 프로그래밍을 좋아합니다. 몇 년 동안 실수를하거나 토끼 구멍을 뚫는 것으로부터 저를 몇 번 구해 주었기 때문입니다. 동일한 입력이 주어지면 출력이 항상 동일하다는 것을 알면 안심입니다.

Syncfusion Blazor 파일 업로드 구성 요소에서 이미지를 미리 보는 방법

Syncfusion Blazor 파일 업로드 구성 요소에서 이미지를 미리 보는 방법

Syncfusion Blazor 파일 업로드는 하나 이상의 파일, 이미지, 문서, 오디오, 비디오 및 기타 파일을 서버에 업로드하기위한 구성 요소입니다. 여러 파일 선택, 진행률 표시 줄, 자동 업로드, 끌어서 놓기, 폴더 (디렉터리) 업로드, 파일을 포함하는 다양한 기능을 갖춘 HTML5 업로드 구성 요소 (<input type =”file”>)의 확장 버전입니다. 검증 등.

6 React 개발자로서 후회

내가 일찍했으면하는 것

6 React 개발자로서 후회

React는 배울 수있는 훌륭한 도구입니다. 그것은 우리가 우리 자신의 방식으로 일을 할 수있게합니다.