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 ,有興趣的可以深入源碼學習下。