亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

TypeScript Reflect Metadata

本節介紹的 Reflect Metadata 主要用來在聲明的時候添加和讀取元數據。通過這種方式給對象添加額外的信息,是不會影響對象的結構的。

1. 慕課解釋

Reflect,翻譯為『反射』,Metadata,翻譯為『元數據』。反射這個概念在 Java 等眾多語言中已經廣泛運用,Reflect Metadata 就是通過裝飾器來給類添加一些自定義的信息,然后通過反射將這些信息提取出來,也可以通過反射來添加這些信息。

2. 安裝使用

通過 npm 安裝這個庫:

npm i reflect-metadata --save

而且需要在 tsconfig.json 中配置:

{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

命令行使用:

tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata

當啟用后,只要 reflect-metadata 庫被引入了,設計階段添加的類型信息可以在運行時使用。

import 'reflect-metadata'

@Reflect.metadata('token', 'aW1vb2M=')
class Employee {

  @Reflect.metadata('level', 'D2')
  salary() {
    console.log('這是個秘密')
  }

  @Reflect.metadata('times', 'daily')
  static meeting() {}

}

const token = Reflect.getMetadata('token', Employee)
const level = Reflect.getMetadata('level', new Employee(), 'salary')
const times = Reflect.getMetadata('times', Employee, 'meeting')

console.log(token) // aW1vb2M=
console.log(level) // D2
console.log(times) // daily

TIPS: 注意, 實例方法與靜態方法取元數據是不同的,實例方法需要在類的實例上取元數據,靜態方法直接在類上取元數據。

3. API

import 'reflect-metadata'
 
// 元數據的命令式定義,定義對象或屬性的元數據
Reflect.defineMetadata(metadataKey, metadataValue, target)
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
 
// 檢查對象或屬性的原型鏈上是否存在元數據鍵
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
 
// 檢查對象或屬性是否存在自己的元數據鍵
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
 
// 獲取對象或屬性原型鏈上元數據鍵的元數據值
let result = Reflect.getMetadata(metadataKey, target)
let result = Reflect.getMetadata(metadataKey, target, propertyKey)
 
// 獲取對象或屬性的自己的元數據鍵的元數據值
let result = Reflect.getOwnMetadata(metadataKey, target)
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey)
 
// 獲取對象或屬性原型鏈上的所有元數據鍵
let result = Reflect.getMetadataKeys(target)
let result = Reflect.getMetadataKeys(target, propertyKey)
 
// 獲取對象或屬性的所有自己的元數據鍵
let result = Reflect.getOwnMetadataKeys(target)
let result = Reflect.getOwnMetadataKeys(target, propertyKey)
 
// 從對象或屬性中刪除元數據
let result = Reflect.deleteMetadata(metadataKey, target)
let result = Reflect.deleteMetadata(metadataKey, target, propertyKey)
 
// 通過裝飾器將元數據應用于構造函數
@Reflect.metadata(metadataKey, metadataValue)
class C {
  // 通過裝飾器將元數據應用于方法(屬性)
  @Reflect.metadata(metadataKey, metadataValue)
  method() {
  }
}

4. 結合裝飾器使用

Reflect Metadata 結合上節介紹的裝飾器:

import 'reflect-metadata'

function get(path: string): MethodDecorator {
  return (target, name) => {
    Reflect.defineMetadata('path', path, target, name)
  }
}

class Employee {
  @get('/init')
  async init() {}
}

const metadata = Reflect.getMetadata('path', new Employee(), 'init')
console.log(metadata) // '/init'

解釋: 如果經常開發 Node.js 的同學對這樣的寫法是不是有些熟悉呢?類方法 init() 上的裝飾器 get() 傳入元數據 '/init',再通過反射拿到這個路由信息,將這些路由信息進行一定的封裝,然后綁定在 koa-router 上,就能達到自動加載路由的功能。

5. 小結

本節介紹了 Reflect Metadata 的一些基礎使用方式,一些基礎庫源碼如 vue-class-component、Angular 均使用了 Reflect Metadata ,有興趣的可以深入源碼學習下。