TypeScript Reflect Metadata
本節(jié)介紹的 Reflect Metadata 主要用來在聲明的時(shí)候添加和讀取元數(shù)據(jù)。通過這種方式給對(duì)象添加額外的信息,是不會(huì)影響對(duì)象的結(jié)構(gòu)的。
1. 慕課解釋
Reflect,翻譯為『反射』,Metadata,翻譯為『元數(shù)據(jù)』。反射這個(gè)概念在 Java 等眾多語言中已經(jīng)廣泛運(yùn)用,Reflect Metadata 就是通過裝飾器來給類添加一些自定義的信息,然后通過反射將這些信息提取出來,也可以通過反射來添加這些信息。
2. 安裝使用
通過 npm 安裝這個(gè)庫:
npm i reflect-metadata --save
而且需要在 tsconfig.json
中配置:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
命令行使用:
tsc --target ES5 --experimentalDecorators --emitDecoratorMetadata
當(dāng)啟用后,只要 reflect-metadata
庫被引入了,設(shè)計(jì)階段添加的類型信息可以在運(yùn)行時(shí)使用。
import 'reflect-metadata'
@Reflect.metadata('token', 'aW1vb2M=')
class Employee {
@Reflect.metadata('level', 'D2')
salary() {
console.log('這是個(gè)秘密')
}
@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: 注意, 實(shí)例方法與靜態(tài)方法取元數(shù)據(jù)是不同的,實(shí)例方法需要在類的實(shí)例上取元數(shù)據(jù),靜態(tài)方法直接在類上取元數(shù)據(jù)。
3. API
import 'reflect-metadata'
// 元數(shù)據(jù)的命令式定義,定義對(duì)象或?qū)傩缘脑獢?shù)據(jù)
Reflect.defineMetadata(metadataKey, metadataValue, target)
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
// 檢查對(duì)象或?qū)傩缘脑玩溕鲜欠翊嬖谠獢?shù)據(jù)鍵
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
// 檢查對(duì)象或?qū)傩允欠翊嬖谧约旱脑獢?shù)據(jù)鍵
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
// 獲取對(duì)象或?qū)傩栽玩溕显獢?shù)據(jù)鍵的元數(shù)據(jù)值
let result = Reflect.getMetadata(metadataKey, target)
let result = Reflect.getMetadata(metadataKey, target, propertyKey)
// 獲取對(duì)象或?qū)傩缘淖约旱脑獢?shù)據(jù)鍵的元數(shù)據(jù)值
let result = Reflect.getOwnMetadata(metadataKey, target)
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey)
// 獲取對(duì)象或?qū)傩栽玩溕系乃性獢?shù)據(jù)鍵
let result = Reflect.getMetadataKeys(target)
let result = Reflect.getMetadataKeys(target, propertyKey)
// 獲取對(duì)象或?qū)傩缘乃凶约旱脑獢?shù)據(jù)鍵
let result = Reflect.getOwnMetadataKeys(target)
let result = Reflect.getOwnMetadataKeys(target, propertyKey)
// 從對(duì)象或?qū)傩灾袆h除元數(shù)據(jù)
let result = Reflect.deleteMetadata(metadataKey, target)
let result = Reflect.deleteMetadata(metadataKey, target, propertyKey)
// 通過裝飾器將元數(shù)據(jù)應(yīng)用于構(gòu)造函數(shù)
@Reflect.metadata(metadataKey, metadataValue)
class C {
// 通過裝飾器將元數(shù)據(jù)應(yīng)用于方法(屬性)
@Reflect.metadata(metadataKey, metadataValue)
method() {
}
}
4. 結(jié)合裝飾器使用
Reflect Metadata 結(jié)合上節(jié)介紹的裝飾器:
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'
解釋: 如果經(jīng)常開發(fā) Node.js 的同學(xué)對(duì)這樣的寫法是不是有些熟悉呢?類方法 init()
上的裝飾器 get()
傳入元數(shù)據(jù) '/init'
,再通過反射拿到這個(gè)路由信息,將這些路由信息進(jìn)行一定的封裝,然后綁定在 koa-router
上,就能達(dá)到自動(dòng)加載路由的功能。
5. 小結(jié)
本節(jié)介紹了 Reflect Metadata 的一些基礎(chǔ)使用方式,一些基礎(chǔ)庫源碼如 vue-class-component
、Angular
均使用了 Reflect Metadata ,有興趣的可以深入源碼學(xué)習(xí)下。