一問了解JavaScript中的元數(shù)據(jù)
在 ES6 的規(guī)范當(dāng)中,ES6 支持元編程,核心是因?yàn)樘峁┝藢?duì) Proxy 和 Reflect 對(duì)象的支持,簡(jiǎn)單來(lái)說這個(gè) API 的作用就是可以實(shí)現(xiàn)對(duì)變量操作的函數(shù)化,也就是反射。
元數(shù)據(jù)
什么是元數(shù)據(jù)
元數(shù)據(jù)是指附加在對(duì)象、類、方法、屬性、參數(shù)上的數(shù)據(jù),它可以用來(lái)幫助實(shí)現(xiàn)某種業(yè)務(wù)功能需要用到的數(shù)據(jù)。
元數(shù)據(jù)的使用
Reflect-metadata- 是 ES7 的一個(gè)提案,它主要用來(lái)聲明的時(shí)候添加和讀取元數(shù)據(jù),Typescript 在 1.5+ 的版本已經(jīng)支持它,你只需要:
npm i reflect-metadata --save
緊接著你要在 tsconfig.json 文件中添加以下配置:
{
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true
}
}
defineMetadata() 和 getMetadata()
該方法是一個(gè)函數(shù)重載,它既可以接收三個(gè)參數(shù),也可以是四個(gè)參數(shù),具體定義如下所示:
function defineMetadata(metadataKey: any, metadataValue: any, target: Object): void; function defineMetadata(metadataKey: any, metadataValue: any, target: Object, propertyKey: string | symbol): void;
它們的參數(shù)分別是:
metadataKey: 用于存儲(chǔ)和檢索元數(shù)據(jù)的鍵;metadataValue: 元數(shù)據(jù)的值;target: 要在其上定義元數(shù)據(jù)的目標(biāo)對(duì)象;propertyKey: 目標(biāo)對(duì)象上的屬性;
有存值的就有取值的,這個(gè)方法也是一個(gè)函數(shù)重載,它的具體定義如下所示:
function getMetadata(metadataKey: any, target: Object, propertyKey: string | symbol): any; function getOwnMetadata(metadataKey: any, target: Object): any;
它的具體使用如下所示:
import "reflect-metadata";
const moment = { address: "廣州" };
Reflect.defineMetadata("method", "hi,叼毛,你上班是不是在摸魚", moment);
console.log(Reflect.getMetadata("method", moment)); // hi,叼毛,你上班是不是在摸魚
Reflect.defineMetadata("method", "hi,靚仔,買菜嗎", moment, moment.address);
console.log(Reflect.getMetadata("method", moment, moment.address)); // hi,靚仔,買菜嗎
metadata()
Reflect.metadata(...) 方法的可以用于類或者類屬性上,它的具體定義如下所示:
function metadata(
metadataKey: any,
metadataValue: any
): {
(target: Function): void;
(target: Object, propertyKey: string | symbol): void;
};
Reflect.metadata 當(dāng)作 Decorator 使用,當(dāng)修飾類時(shí),在類上添加元數(shù)據(jù),當(dāng)修飾類屬性時(shí),在類原型的屬性上添加元數(shù)據(jù):
import "reflect-metadata";
@Reflect.metadata("inClass", "哇哈哈哈哈")
class Test {
@Reflect.metadata("inMethod", "我要喝喜之郎,我要當(dāng)太空人")
public hello(): string {
return "hello world";
}
}
console.log(Reflect.getMetadata("inClass", Test)); // 哇哈哈哈哈
console.log(Reflect.getMetadata("inMethod", new Test(), "hello")); // 我要喝喜之郎,我要當(dāng)太空人
在這里可能會(huì)有人就好奇了,這里面的方法怎么和上面的不一樣啊,上面的是 defineMetadata(...),而這里直接用的 metadata(...),這是為什么呢?
答案是 defineMetadata(...) 它要確定你要是在哪里定義的元數(shù)據(jù),而后者是直接以裝飾器的方式調(diào)用,它已經(jīng)明確知道了你就是給這個(gè)類來(lái)定義的元數(shù)據(jù)。
獲取類型信息并賦值
我們可以通過 Reflect.getMetadata 方法來(lái)獲取屬性類型,并且對(duì)該屬性進(jìn)行賦值,如下操作所示:
import "reflect-metadata";
function Prop(): PropertyDecorator {
return (target, key: string) => {
const type = Reflect.getMetadata("design:type", target, key);
console.log(`${key} type: ${type.name}`);
target[key] = "moment";
};
}
class SomeClass {
@Prop()
public nickname!: string;
}
console.log(new SomeClass().nickname); // moment
例如在 vue-property-decorator 中通過使用 Reflect.getMetadata API,Prop Decorator 能獲取屬性類型傳至 Vue,簡(jiǎn)要代碼如下:
import { Vue, Component, PropSync } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@PropSync('name', { type: String }) syncedName!: string
}
這樣的寫法就等同于以下代碼所示:
export default {
props: {
name: {
type: String,
},
},
computed: {
syncedName: {
get() {
return this.name
},
set(value) {
this.$emit('update:name', value)
},
},
},
}
除了能獲取屬性類型以外,通過 Reflect.getMetadata("design:paramtypes", target, key) 和 Reflect.getMetadata("design:returntype", target, key) 可以分別獲取函數(shù)參數(shù)類型和返回值類型,具體代碼如下所示:
import "reflect-metadata";
function Func(): PropertyDecorator {
return (target, key: string) => {
console.log(Reflect.getMetadata("design:paramtypes", target, key)); // 函數(shù)參數(shù)類型
console.log(Reflect.getMetadata("design:returntype", target, key)); // 返回值類型
};
}
class SomeClass {
@Func()
moment(value: boolean): string {
return " ";
}
}
自定義 metadataKey
除了能獲取類型信息外,常用與自定義 metadataKey,并在合適的實(shí)際獲取它的值,具體實(shí)例代碼如下所示:
import "reflect-metadata";
function classDecorator(): ClassDecorator {
return (target) => {
Reflect.defineMetadata("class", "類裝飾器", target);
};
}
function methodDecorator(): MethodDecorator {
return (target, key, descriptor) => {
Reflect.defineMetadata("method", "方法裝飾器", target, key);
};
}
@classDecorator()
class SomeClass {
@methodDecorator()
someMethod() {}
}
console.log(Reflect.getMetadata("class", SomeClass)); // 類裝飾器
console.log(Reflect.getMetadata("method", new SomeClass(), "someMethod")); // 方法裝飾器
參考文獻(xiàn)
總結(jié)
元數(shù)據(jù)的應(yīng)用場(chǎng)景很多,其中 NestJs 就是使用了大量的元數(shù)組實(shí)現(xiàn)了控制反轉(zhuǎn)和依賴注入,將會(huì)在下一篇文章中講到,本篇文章到此結(jié)束。
到此這篇關(guān)于一問了解JavaScript中的元數(shù)據(jù)的文章就介紹到這了,更多相關(guān)JavaScript 元數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
webpack4之SplitChunksPlugin使用指南
這篇文章主要介紹了webpack4之SplitChunksPlugin使用指南,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-06-06
javascript顯示動(dòng)態(tài)時(shí)間的方法匯總
本文給大家匯總介紹了3種javascript實(shí)現(xiàn)動(dòng)態(tài)顯示時(shí)間的方法及詳細(xì)示例,有需要的小伙伴可以參考下2018-07-07
帶你使用webpack快速構(gòu)建web項(xiàng)目的方法
這篇文章主要介紹了帶你使用webpack快速構(gòu)建web項(xiàng)目的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
微信小程序獲取用戶信息及手機(jī)號(hào)(后端TP5.0)
這篇文章主要為大家詳細(xì)介紹了微信小程序獲取用戶信息及手機(jī)號(hào),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
js和jQuery以及easyui實(shí)現(xiàn)對(duì)下拉框的指定賦值方法
下面小編就為大家分享一篇js和jQuery以及easyui實(shí)現(xiàn)對(duì)下拉框的指定賦值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-01-01
JavaScript訪問本地文件夾的幾種實(shí)現(xiàn)方法
由于安全限制無(wú)法直接訪問用戶的本地文件或文件夾,本文主要介紹了JavaScript訪問本地文件夾的幾種實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06
moment.js 計(jì)算當(dāng)前一周、一月對(duì)應(yīng)日期的實(shí)例
這篇文章主要介紹了moment.js 計(jì)算當(dāng)前一周、一月對(duì)應(yīng)日期的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
js對(duì)象轉(zhuǎn)json數(shù)組的簡(jiǎn)單實(shí)現(xiàn)案例
本篇文章主要是對(duì)js對(duì)象轉(zhuǎn)json數(shù)組的簡(jiǎn)單實(shí)現(xiàn)案例進(jìn)行了介紹,需要的朋友可以過來(lái)參考下,希望對(duì)大家有所幫助2014-02-02

