今天就跟大家聊聊有關(guān)如何在JavaScript中使用Reflect Metadata,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
創(chuàng)新互聯(lián)長(zhǎng)期為超過(guò)千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為大通企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作,大通網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。Metadata
想必對(duì)于其他語(yǔ)言的 Coder 來(lái)說(shuō),比如說(shuō) Java 或者 C#,Metadata 是很熟悉的。最簡(jiǎn)單的莫過(guò)于通過(guò)反射來(lái)獲取類屬性上面的批注(在 JS 當(dāng)中,也就是所謂的裝飾器)。從而可以更加優(yōu)雅的對(duì)代碼進(jìn)行控制。
而 JS 現(xiàn)在有裝飾器,雖然現(xiàn)在還在 Stage2 階段。但是 JS 的裝飾器更多的是存在于對(duì)函數(shù)或者屬性進(jìn)行一些操作,比如修改他們的值,代理變量,自動(dòng)綁定 this 等等功能。
所以,后文當(dāng)中我就使用 TypeScript 來(lái)進(jìn)行講解,因?yàn)?TypeScript 已經(jīng)完整的實(shí)現(xiàn)了裝飾器。
雖然 Babel 也可以,但是需要各種配置,人懶,不想配置那么多。
但是卻無(wú)法實(shí)現(xiàn)通過(guò)反射來(lái)獲取究竟有哪些裝飾器添加到這個(gè)類/方法上。
于是 Reflect Metadata 應(yīng)運(yùn)而生。
Reflect Metadata
Relfect Metadata,簡(jiǎn)單來(lái)說(shuō),你可以通過(guò)裝飾器來(lái)給類添加一些自定義的信息。然后通過(guò)反射將這些信息提取出來(lái)。當(dāng)然你也可以通過(guò)反射來(lái)添加這些信息。 就像是下面這個(gè)例子所示。
@Reflect.metadata('name', 'A') class A { @Reflect.metadata('hello', 'world') public hello(): string { return 'hello world' } } Reflect.getMetadata('name', A) // 'A' Reflect.getMetadata('hello', new A()) // 'world' // 這里為什么要用 new A(),用 A 不行么?后文會(huì)講到
是不是很簡(jiǎn)單,那么我簡(jiǎn)單來(lái)介紹一下~
概念
首先,在這里有四個(gè)概念要區(qū)分一下:
Metadata Key {Any} 后文簡(jiǎn)寫(xiě) k。元數(shù)據(jù)的 Key,對(duì)于一個(gè)對(duì)象來(lái)說(shuō),他可以有很多元數(shù)據(jù),每一個(gè)元數(shù)據(jù)都對(duì)應(yīng)有一個(gè) Key。一個(gè)很簡(jiǎn)單的例子就是說(shuō),你可以在一個(gè)對(duì)象上面設(shè)置一個(gè)叫做 'name' 的 Key 用來(lái)設(shè)置他的名字,用一個(gè) 'created time' 的 Key 來(lái)表示他創(chuàng)建的時(shí)間。這個(gè) Key 可以是任意類型。在后面會(huì)講到內(nèi)部本質(zhì)就是一個(gè) Map 對(duì)象。
Metadata Value {Any} 后文簡(jiǎn)寫(xiě) v。元數(shù)據(jù)的類型,任意類型都行。
Target {Object} 后文簡(jiǎn)寫(xiě) o。表示要在這個(gè)對(duì)象上面添加元數(shù)據(jù)
Property {String|Symbol} 后文簡(jiǎn)寫(xiě) p。用于設(shè)置在那個(gè)屬性上面添加元數(shù)據(jù)。大家可能會(huì)想,這個(gè)是干什么用的,不是可以在對(duì)象上面添加元數(shù)據(jù)了么?其實(shí)不僅僅可以在對(duì)象上面添加元數(shù)據(jù),甚至還可以在對(duì)象的屬性上面添加元數(shù)據(jù)。其實(shí)大家可以這樣理解,當(dāng)你給一個(gè)對(duì)象定義元數(shù)據(jù)的時(shí)候,相當(dāng)于你是默認(rèn)指定了 undefined 作為 Property。 下面有一個(gè)例子大家可以看一下。
大家明白了上面的概念之后,我之前給的那個(gè)例子就很簡(jiǎn)單了~不用我多說(shuō)了。
安裝/使用
下面不如正題,我們?cè)趺撮_(kāi)始使用 Reflect Metadata 呢?
首先,你需要安裝 reflect-metadata polyfill,然后引入之后就可以看到在 Reflect 對(duì)象下面有很多關(guān)于 Metadata 的函數(shù)了。因?yàn)檫@個(gè)還沒(méi)有進(jìn)入正式的協(xié)議,所以需要安裝墊片使用。
啥,Reflect 是啥,一個(gè)全局變量而已。
你不需要擔(dān)心這個(gè)墊片的質(zhì)量,因?yàn)檫B Angular 都在使用呢,你怕啥。
之后你就可以安裝我上面寫(xiě)的示例,在 TypeScript 當(dāng)中去跑了。
類/屬性/方法 裝飾器
看這個(gè)例子。
@Reflect.metadata('name', 'A') class A { @Reflect.metadata('name', 'hello') hello() {} } const objs = [A, new A, A.prototype] const res = objs.map(obj => [ Reflect.getMetadata('name', obj), Reflect.getMetadata('name', obj, 'hello'), Reflect.getOwnMetadata('name', obj), Reflect.getOwnMetadata('name', obj ,'hello') ]) // 大家猜測(cè)一下 res 的值會(huì)是多少?
想好了么?再給你 10 秒鐘
10
9
8
7
6
5
4
3
2
1
res
[ ['A', undefined, 'A', undefined], [undefined, 'hello', undefined, undefined], [undefined, 'hello', undefined, 'hello'], ]
那么我來(lái)解釋一下為什么回是這樣的結(jié)果。
首先所有的對(duì)類的修飾,都是定義在類這個(gè)對(duì)象上面的,而所有的對(duì)類的屬性或者方法的修飾,都是定義在類的原型上面的,并且以屬性或者方法的 key 作為 property,這也就是為什么 getMetadata 會(huì)產(chǎn)生這樣的效果了。
那么帶 Own 的又是什么情況呢?
這就要從元數(shù)據(jù)的查找規(guī)則開(kāi)始講起了
原型鏈查找
類似于類的繼承,查找元數(shù)據(jù)的方式也是通過(guò)原型鏈進(jìn)行的。
就像是上面那個(gè)例子,我實(shí)例化了一個(gè) new A(),但是我依舊可以找到他原型鏈上的元數(shù)據(jù)。
舉個(gè)例子
class A { @Reflect.metadata('name', 'hello') hello() {} } const t1 = new A() const t2 = new A() Reflect.defineMetadata('otherName', 'world', t2, 'hello') Reflect.getMetadata('name', t1, 'hello') // 'hello' Reflect.getMetadata('name', t2, 'hello') // 'hello' Reflect.getMetadata('otherName', t2, 'hello') // 'world' Reflect.getOwnMetadata('name', t2, 'hello') // undefined Reflect.getOwnMetadata('otherName', t2, 'hello') // 'world'
用途
其實(shí)所有的用途都是一個(gè)目的,給對(duì)象添加額外的信息,但是不影響對(duì)象的結(jié)構(gòu)。這一點(diǎn)很重要,當(dāng)你給對(duì)象添加了一個(gè)原信息的時(shí)候,對(duì)象是不會(huì)有任何的變化的,不會(huì)多 property,也不會(huì)有的 property 被修改了。
但是可以衍生出很多其他的用途。
Anuglar 中對(duì)特殊字段進(jìn)行修飾 (Input),從而提升代碼的可讀性。
可以讓裝飾器擁有真正裝飾對(duì)象而不改變對(duì)象的能力。讓對(duì)象擁有更多語(yǔ)義上的功能。
API
namespace Reflect { // 用于裝飾器 metadata(k, v): (target, property?) => void // 在對(duì)象上面定義元數(shù)據(jù) defineMetadata(k, v, o, p?): void // 是否存在元數(shù)據(jù) hasMetadata(k, o, p?): boolean hasOwnMetadata(k, o, p?): boolean // 獲取元數(shù)據(jù) getMetadata(k, o, p?): any getOwnMetadata(k, o, p?): any // 獲取所有元數(shù)據(jù)的 Key getMetadataKeys(o, p?): any[] getOwnMetadataKeys(o, p?): any[] // 刪除元數(shù)據(jù) deleteMetadata(k, o, p?): boolean }
大家可能注意到,針對(duì)某些操作,會(huì)有 Own 的函數(shù)。這是因?yàn)橛械牟僮魇强梢酝ㄟ^(guò)原型鏈進(jìn)行操作的。這個(gè)后文講解。
深入 Reflect Metadata
實(shí)現(xiàn)原理
如果你去翻看官網(wǎng)的文檔,他會(huì)和你說(shuō),所有的元數(shù)據(jù)都是存在于對(duì)象下面的 [[Metadata]] 屬性下面。一開(kāi)始我也是這樣認(rèn)為的,新建一個(gè) Symbol('Metadata'),然后將元數(shù)據(jù)放到這個(gè) Symbol 對(duì)應(yīng)的 Property 當(dāng)中。直到我看了源碼才發(fā)現(xiàn)并不是這樣。請(qǐng)看例子
@Reflect.metadata('name', 'A') class A {} Object.getOwnPropertySymbols(A) // []
哈哈,并沒(méi)有所謂的 Symbol,那么這些元數(shù)據(jù)都存在在哪里呢?
其實(shí)是內(nèi)部的一個(gè) WeakMap 中。他正是利用了 WeakMap 不增加引用計(jì)數(shù)的特點(diǎn),將對(duì)象作為 Key,元數(shù)據(jù)集合作為 Value,存到 WeakMap 中去。
如果你認(rèn)真探尋的話,你會(huì)發(fā)現(xiàn)其內(nèi)部的數(shù)據(jù)結(jié)構(gòu)其實(shí)是這樣的
WeakMap<any, Map<any, Map<any, any>>>
是不是超級(jí)繞,但是我們從調(diào)用的角度來(lái)思考,這就一點(diǎn)都不繞了。
weakMap.get(o).get(p).get(k)
看完上述內(nèi)容,你們對(duì)如何在JavaScript中使用Reflect Metadata有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道,感謝大家的支持。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
文章名稱:如何在JavaScript中使用ReflectMetadata-創(chuàng)新互聯(lián)
標(biāo)題鏈接:http://vcdvsql.cn/article16/cedgdg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站制作、微信公眾號(hào)、企業(yè)建站、服務(wù)器托管、Google、App開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容