"reflect-metadata"패키지 소개 및 ECMAScript 제안

이 레슨에서는 reflect-metadata데코레이터를 디자인하기 위해 TypeScript에서 사용 하는 패키지를 살펴볼 것입니다. 이 패키지는 주로 ReflectAPI의 "메타 데이터 확장"ECMAScript 제안 을위한 폴리 필로 사용됩니다 .

(출처 : unsplash.com)

간단히 말해 메타 데이터 는 실제 데이터에 대한 추가 정보입니다. 예를 들어 변수가 배열을 나타내는 경우 해당 배열 의 길이 는 메타 데이터입니다. 마찬가지로 해당 배열의 각 요소는 데이터이지만 이러한 요소의 데이터 유형은 메타 데이터입니다. 느슨하게 말해서 메타 데이터는 프로그램의 실제 문제는 아니지만 작업을 더 빨리 달성하는 데 도움이 될 수 있습니다.

작은 예를 들어 보겠습니다. 다른 기능에 대한 정보를 인쇄하는 기능을 디자인해야하는 경우 어떤 정보를 인쇄 하시겠습니까?

(reflect-metadata / func-info.js)

위의 예에서 funcInfo함수는 인수로 함수를 취하고 포함 된 문자열을 반환하는 함수 이름인수의 수 이 기능을 허용합니다. 이 정보는 함수 자체에 포함되어 있지만 실제로는 거의 사용하지 않습니다. 따라서, func.namefunc.length메타 데이터로서 간주 될 수있다.

에서 속성 기술자의 교훈, 우리는 개체의 속성의 속성 설명에 대해 배웠습니다. 속성 설명자는 개체의 속성이 작동하는 방식을 구성하는 개체입니다. 예를 들어 객체의 속성을 읽기 전용 ( 쓰기 불가능) 또는 열거 불가능으로 설정할 수 있습니다 .

속성 설명자는 객체 속성의 메타 데이터와 같습니다. 메서드 또는 메서드 호출을 사용하여 찾을 때까지 표시되지 않습니다 . 이 메타 데이터를 사용자 지정하여 개체 및 해당 속성의 동작 방식을 변경할 수 있으며 속성 설명자 단원 에서 배웠습니다 .Object.getPropertyDescriptor()Reflect.getPropertyDescriptor()

메타 데이터는 메타 프로그래밍을 가능하게합니다. 메타 데이터는 반성, 특히 내성을 위해 필요합니다 . 예를 들어, 함수가 수신하도록 설계된 인수의 수에 따라 프로그램 동작을 변경할 수 있습니다.

이제 여러분은 메타 데이터의 힘을 이해할 수 있습니다. 메타 프로그래밍을위한 모든 종류의 흥미로운 가능성을 열어줍니다. 그러나 우리는 자바 스크립트가 메타 프로그래밍을 위해 제공해야하는 것에 제한을받습니다. 이전 단원 에서 이러한 기능을 살펴 보았습니다 . 개체에 사용자 지정 메타 데이터를 추가 할 수있는 기능이있는 경우에만 가능합니다. 그것은 거의 모든 문제를 해결할 것입니다 🥺.

Reflect정확히 그렇게하는의 메타 데이터 확장을 환영합시다 . 개체 및 개체 속성에 사용자 지정 메타 데이터를 추가하기 위해 Reflect의 기능을 확장하는 제안이 있습니다.

기다림!!! 아직 제안이고 ECMAScript에 제출되지 않았기 때문에 지금은 그렇게 흥분하지 않을 것입니다. 그러나 여기 에서 자세한 제안 사양을 찾을 수 있으며 TC39에 제출되지 않은 이유를 찾고 있다면 GitHub 문제 스레드가 도움이 될 수 있습니다.

TypeScript 개발자이고 Decorators와 함께 작업했다면 reflect-metadata패키지 에 대해 들어 보셨을 것 입니다. 이 패키지를 사용하면 클래스, 클래스 필드 등에 사용자 정의 메타 데이터를 추가 할 수 있습니다. 그러나이 단원에서는 TypeScript 또는 데코레이터에 대해 설명하지 않습니다. 아마도 우리는 그것들을 별도의 수업에서 다룰 수 있습니다. 이 강의에서는 어떤 reflect-metadata패키지가 제공하는지, 무엇을 할 수 있는지 살펴 보겠습니다 .

반영 교훈, 우리가 배운 ReflectAPI 개체를 검사하고 자신의 행동을 변경하는 메타 데이터를 추가 할 수있는 좋은 도구입니다. 예를 들어 Reflect.has메서드 in는 객체 또는 프로토 타입 체인에 속성이 있는지 확인하는 연산자 처럼 작동합니다. 이 Reflect.setPrototypeOf메서드는 개체에 사용자 지정 프로토 타입을 추가하므로 동작이 변경됩니다. 반사에Reflect 사용되는 많은 방법을 제공합니다 .

메타 데이터 제안 ( 사양 여기에 ) 몇 가지 제안 새로운 방법 확장에 Reflect의 능력을. 그러나 이러한 메서드는 JavaScript의 메타 프로그래밍 지원을 강화하기위한 것일뿐입니다. 간단히 살펴 보겠습니다.

// define metadata on a target object
Reflect.defineMetadata(
  metadataKey,
  metadataValue,
  target
);
// define metadata on a target's property
Reflect.defineMetadata(
  metadataKey,
  metadataValue,
  target,
  propertyKey
);

// get metadata associated with target
let result = Reflect.getMetadata(
  metadataKey,
  target
);
// get metadata associated with target's property
let result = Reflect.getMetadata(
  metadataKey,
  target,
  propertyKey
);

에서 이전의 교훈, 우리는 또한에 대해 알게 내부 슬롯내부 방법 . 이는 해당 데이터에 대해 작동하는 데이터 및 논리를 보유하는 개체의 내부 속성 및 메서드입니다.

이 메타 데이터 제안은 [[Metadata]]모든 일반 개체에 대한 내부 슬롯을 제안 합니다. 이 내부 슬롯은 객체에 메타 데이터가 없음 null을 의미 target하거나 Map대상 또는 해당 속성에 대해 다른 키가있는 메타 데이터를 보유 하는 요소 일 수 있습니다 .

Reflect.defineMetadata부르는 [[DefineMetadata]]내부 방법 및 Reflect.getMetadata사용 [[GetMetadata]]을 가져 오기 위해 내부 방법.

이것을 실제로 봅시다. 하지만 그 전에 reflect-metadata패키지 를 설치해야 합니다. 이 GitHub 저장소 에서 설치 지침을 찾을 수 있습니다 . npm install reflect-metadata명령 을 사용하여 설치할 수 있습니다 .

(reflect-metadata / metadata-intro.js)

require('reflect-metadata')import 문은 특별하다. 이 가져옵니다 reflect-metadata과 같은 제안 된 방법을 추가 패키지 defineMetadata받는 Reflect런타임에 객체와 우리의 유형을 보면이를 확인할 수 있습니다 Reflect.defineMetadata기능. 따라서이 패키지는 기술적으로 polyfill 입니다.

그런 다음 우리는 정의 target우리가 키가 몇 가지 메타 데이터를 추가하는에 객체를 version, info하고 is. versioninfo상의 직접 추가 한 target동안은 is온 추가 된 name속성입니다. 메타 데이터 값은 가능한 JavaScript 값입니다.

Reflect.getMetadata와 관련된 메타 데이터를 반환 target또는 속성을. 메타 데이터가 없으면을 반환합니다 undefined. 이러한 메서드를 사용하면 모든 메타 데이터를 모든 개체 또는 해당 속성과 연결할 수 있습니다.

target당신이 로그에서 볼 수있는 자체 또는 그 속성에 메타 데이터를 등록하는 동안 변이되지 않습니다. [[Metadata]]실제로이 메타 데이터는 내부 슬롯에 저장 되지만이 폴리 필은를 사용 WeakMap하여 target.

hasMetadata메서드를 사용하여 메타 데이터 값의 존재 여부를 확인하고에 getMetadataKeys등록 된 메타 데이터 값의 키를 반환 target할 수 있습니다. 메타 데이터 값을 제거하려면 deleteMetadata메서드를 사용할 수 있습니다 .

// check for presence of a metadata key (returns a boolean)
let result = Reflect.hasMetadata(key, target);
let result = Reflect.hasMetadata(key, target, property);
// get all metadata keys (returns an Array)
let result = Reflect.getMetadataKeys(target);
let result = Reflect.getMetadataKeys(target, property);
// delete metadata with a key (returns a boolean)
let result = Reflect.deleteMetadata(key, target);
let result = Reflect.deleteMetadata(key, target, property);
(reflect-metadata/metadata-other-methods.js)

// get metadata value of an own metadata key
let result = Reflect.getOwnMetadata(key, target);
let result = Reflect.getOwnMetadata(key, target, property);
// check for presence of an own metadata key
let result = Reflect.hasOwnMetadata(key, target);
let result = Reflect.hasOwnMetadata(key, target, property);
// get all own metadata keys
let result = Reflect.getOwnMetadataKeys(target);
let result = Reflect.getOwnMetadataKeys(target, property);
(reflect-metadata/metadata-prototype.js)
(reflect-metadata / metadata-prototype.js)

이 제안은 또한 Reflect.metadata방법 을 제안 하지만 Reflect위에서 본 것처럼 일반적인 방법은 아닙니다 . 이 메서드는 데코레이터 팩토리 로, 일부 인수와 함께 호출되면 클래스 또는 클래스 필드를 장식하는 데 사용할 수있는 데코레이터 함수를 반환합니다.

" JavaScript (ECMAScript) 데코레이터에 대한 최소 가이드 "강의 에서 JavaScript 데코레이터에 대해 배웠습니다 . JavaScript 데코레이터는 현재 ECMAScript 표준의 일부가 아니며 제안은 여전히 2 단계에 있습니다. 따라서 데코레이터 제안 은 아직 활발히 개발 중입니다.

@Reflect.metadata(metadataKey, metadataValue)
class MyClass {
  @Reflect.metadata(metadataKey, metadataValue)
  methodName(){
    // ...
  }
}

이것이 어떻게 작동하는지 궁금하다면 실제로는 매우 간단합니다. Reflect.metadata메서드 호출은 장식 기능을 반환합니다. 이 데코레이터 함수 Reflect.defineMetadata는 클래스 또는 속성과 같이 데코 레이팅중인 엔티티에 메타 데이터를 추가하는 내부를 구현 합니다.

여기서 문제는 reflect-metadata패키지 ( polyfill ) 가 데코레이터 제안 의 레거시 버전 을 구현 한다는 것입니다. TypeScript는 또한 데코레이터 구현을 위해 동일한 버전을 구현합니다. 데코레이터 에 대한 내 기사를 따라 데코레이터 를 디자인하는 레거시 패턴을 이해할 수 있습니다 .

이 패키지가 제공하는 데코레이터 패턴을 JavaScript로 기본적으로 구현할 수 없기 때문에 TypeScript를 사용하여 시연해야합니다. 그러나이 프로그램의 유형을 무시하면 JavaScript 프로그램과 구문 상 유사하게 보입니다.

💡 이 babel 플러그인 을 사용 하여 기존 데코레이터가있는 JavaScript를 기본적으로 작동하는 바닐라 JavaScript 코드로 변환 할 수도 있습니다 .

(reflect-metadata / metadata-decorator.ts)

위의 예에서 볼 수 있듯이 나중에 메서드를 사용하여 추출한 @Reflect.metadata메타 데이터를 Person클래스 에 성공적으로 추가 할 수있었습니다 Reflect.getMetadata(<key>, Person). 호출에 myDecorator의해 반환 된 데코레이터를 반환하는 자체 데코레이터 팩토리를 만들 수도 있습니다 Reflect.metadata.

💡 TypeScript 의 데코레이터 패턴과 reflect-metadata별도의 TypeScript 강의 (곧 제공 예정)에서 패키지 사용에 대해 자세히 알아 봅니다 .

그것은 reflect-metadata패키지 및 메타 데이터 제안을위한 것입니다. 이 제안의 사용 사례는 끝이 없습니다. 이것이 자바 스크립트 메타 프로그래밍의 성배라고 말할 수 있습니다. 이것이 ECMAScript 제안의 일부가 될 때까지 기다려야합니다.

에서 프록시 교훈, 우리는 모든 프록시 사실을 알게 handler트랩이 동등한이 Reflect정적 방법. reflect-metadata패키지가 지원을 제공하기를 바랐 Proxy지만 현재 는 지원 하지 않습니다. GitHub 문제 에서이 기능을 추적 할 수 있습니다 .

🙋 이 제안에 대해 어떻게 생각하는지 댓글로 알려주세요.

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

Suggested posts

JavaScript의 이벤트 루프

호출 스택, 웹 API, 이벤트 대기열, 마이크로 작업, 매크로 작업

JavaScript의 이벤트 루프

이벤트 루프는 JavaScript의 비동기 프로그래밍의 비밀입니다. JS는 단일 스레드에서 모든 작업을 실행하지만 몇 가지 스마트 데이터 구조를 사용하면 멀티 스레딩의 환상을 얻을 수 있습니다.

매일 필요한 10 가지 유용한 자바 스크립트 코드 스 니펫

항상 필요한 코드

매일 필요한 10 가지 유용한 자바 스크립트 코드 스 니펫

프로그래머는 항상 새로운 일을하지만 모든 프로젝트에 포함되어야하는 기본적이고 규칙적인 것들이 존재합니다. 여기에서 새로운 것을 찾을 수있는 코드 스 니펫을 언급했습니다.