最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript Reflect Metadata實(shí)現(xiàn)詳解

 更新時(shí)間:2019年12月12日 09:27:59   作者:XGHeaven  
這篇文章主要介紹了JavaScript Reflect Metadata實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

引言

在 ES6 的規(guī)范當(dāng)中,就已經(jīng)存在 Reflect API 了。簡(jiǎn)單來(lái)說(shuō)這個(gè) API 的作用就是可以實(shí)現(xiàn)對(duì)變量操作的函數(shù)化,也就是反射。具體的關(guān)于這個(gè) API 的內(nèi)容,可以查看這個(gè)教程

然而我們?cè)谶@里講到的,卻是 Reflect 里面還沒(méi)有的一個(gè)規(guī)范,那么就是 Reflect Metadata。

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ū)分一下:

  1. 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ì)象。
  2. Metadata Value {Any} 后文簡(jiǎn)寫(xiě) v。元數(shù)據(jù)的類型,任意類型都行。
  3. Target {Object} 后文簡(jiǎn)寫(xiě) o。表示要在這個(gè)對(duì)象上面添加元數(shù)據(jù)
  4. 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)

先根據(jù)對(duì)象獲取,然后在根據(jù)屬性,最后根據(jù)元數(shù)據(jù)的 Key 獲取最終要的數(shù)據(jù)。

End

因?yàn)?Reflect Metadata 實(shí)在是比較簡(jiǎn)單,這里就不多講解了。更多內(nèi)容請(qǐng)查看Spec

題外話

其實(shí)看了源碼之后還是挺驚訝的,按照一般的套路,很多 polyfill 會(huì)讓你提供一些前置的 polyfill 之后,當(dāng)前的 polyfill 才能使用。但是 reflect-metadata 竟然內(nèi)部自己實(shí)現(xiàn)了很多的 polyfill 和算法。比如 Map, Set, WeakMap, UUID。最驚訝的莫過(guò)于 WeakMap 了。不是很仔細(xì)的閱讀了一下,好像還是會(huì)增加引用計(jì)數(shù)。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • JavaScript優(yōu)化以及前段開(kāi)發(fā)小技巧

    JavaScript優(yōu)化以及前段開(kāi)發(fā)小技巧

    隨著前端技術(shù)的發(fā)展,前端業(yè)務(wù)越來(lái)越繁重,這大大增加了JS代碼量。因此,要提高Web的性能,我們不僅需要關(guān)注頁(yè)面加載的時(shí)間,還要注重在頁(yè)面上操作的響應(yīng)速度。那么,接下來(lái)我們討論幾種能夠提高JavaScript效率的方法。
    2017-02-02
  • WEB 瀏覽器兼容 推薦收藏

    WEB 瀏覽器兼容 推薦收藏

    這是我總結(jié)多年的一個(gè)小文檔,最近看見(jiàn)有人咨詢?yōu)g覽器兼容的問(wèn)題,就貢獻(xiàn)出來(lái)。
    2010-05-05
  • 一步一步教你寫(xiě)淡入淡出帶注釋的圖片輪播插件(二)

    一步一步教你寫(xiě)淡入淡出帶注釋的圖片輪播插件(二)

    開(kāi)始之前,還是說(shuō)說(shuō)前文提到的關(guān)于把所有函數(shù)都寫(xiě)在一個(gè)閉包內(nèi)的優(yōu)化問(wèn)題。前文也提到了,因?yàn)槲覀冊(cè)诔跏蓟臅r(shí)候要調(diào)用的只是init,所以可以只把init寫(xiě)入閉包,其他功能函數(shù)作為init的原型繼承方法來(lái)調(diào)用。
    2010-10-10
  • js遍歷json的key和value的實(shí)例

    js遍歷json的key和value的實(shí)例

    下面小編就為大家?guī)?lái)一篇js遍歷json的key和value的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • JS圖片等比例縮放方法完整示例

    JS圖片等比例縮放方法完整示例

    這篇文章主要介紹了JS圖片等比例縮放方法,結(jié)合完整實(shí)例形式分析了javascript針對(duì)頁(yè)面圖片元素屬性操作的相關(guān)技巧,需要的朋友可以參考下
    2016-08-08
  • jquery插件錦集【推薦】

    jquery插件錦集【推薦】

    本文主要分享了jquery插件: 時(shí)鐘效果; 倒計(jì)時(shí); 全選效果; tab點(diǎn)擊切換; tab鼠標(biāo)移動(dòng)切換; 文本輸入搜索等。具有很好的參考價(jià)值需要的朋友一起來(lái)看下吧
    2016-12-12
  • 瀏覽器兼容的JS寫(xiě)法總結(jié)

    瀏覽器兼容的JS寫(xiě)法總結(jié)

    瀏覽器兼容的JS寫(xiě)法總結(jié),涵蓋的內(nèi)容很全面,感興趣的小伙伴們可以參考一下
    2016-04-04
  • JS實(shí)現(xiàn)距離上次刷新已過(guò)多少秒示例

    JS實(shí)現(xiàn)距離上次刷新已過(guò)多少秒示例

    這篇文章主要介紹了JS如何實(shí)現(xiàn)距離上次刷新已過(guò)多少秒,需要的朋友可以參考下
    2014-05-05
  • javascript執(zhí)行上下文詳解

    javascript執(zhí)行上下文詳解

    執(zhí)行上下文可以說(shuō)是js代碼執(zhí)行的一個(gè)環(huán)境,存放了代碼執(zhí)行所需的變量,變量查找的作用域鏈規(guī)則以及this指向等。同時(shí),它也是js很底層的東西,很多的問(wèn)題如變量提升、作用域鏈和閉包等都可以在執(zhí)行上下文中找到答案,所以這也是我們學(xué)習(xí)執(zhí)行上下文的原因
    2023-05-05
  • JavaScript實(shí)現(xiàn)PDF加載與顯示的技術(shù)指南

    JavaScript實(shí)現(xiàn)PDF加載與顯示的技術(shù)指南

    在Web開(kāi)發(fā)中,利用JavaScript技術(shù)加載和顯示PDF文件是一種常見(jiàn)需求,尤其是在文檔預(yù)覽或在線閱讀器的開(kāi)發(fā)中,本文詳細(xì)介紹了使用JavaScript庫(kù),特別是PDF.js,來(lái)實(shí)現(xiàn)PDF文件在瀏覽器中的加載和顯示,需要的朋友可以參考下
    2025-08-08

最新評(píng)論

花垣县| 喜德县| 随州市| 隆林| 灌阳县| 威远县| 宣武区| 杭锦旗| 临沂市| 高淳县| 丰镇市| 综艺| 临桂县| 车致| 砚山县| 土默特左旗| 扶余县| 黔西县| 剑川县| 勃利县| 吐鲁番市| 海口市| 法库县| 铜川市| 汉源县| 元氏县| 贞丰县| 德化县| 沾益县| 山阴县| 贞丰县| 兰考县| 景德镇市| 弋阳县| 静宁县| 洛川县| 交城县| 思茅市| 湖南省| 墨脱县| 行唐县|