從java注解漫談到typescript裝飾器——注解與裝飾器

之前整理過(guò)《Java注解(批注)的基本原理》钮惠,在java里面运授,帜羊,注解(Annotation)是油鹽凭涂,對(duì)于JavaScript來(lái)說(shuō)断傲,還中世紀(jì)歐洲的東方香料

裝飾器和注解

裝飾器和注解之前也搞不清他們的具體理念败徊,覺(jué)得都是基于元編程實(shí)現(xiàn)辟拷,注解就是裝飾模式的一種吧撞羽。

注解(Annotation):僅提供附加元數(shù)據(jù)支持,并不能實(shí)現(xiàn)任何操作衫冻。需要另外的 Scanner 根據(jù)元數(shù)據(jù)執(zhí)行相應(yīng)操作诀紊。

裝飾器(Decorator):僅提供定義劫持,可以對(duì)類(lèi)隅俘,類(lèi)的方法邻奠,類(lèi)的屬性以及類(lèi)的方法的入?yún)⑦M(jìn)行修改笤喳。不提供元數(shù)據(jù)的支持。

注解與裝飾器兩者之間的聯(lián)系:

通過(guò)注解添加元數(shù)據(jù)碌宴,然后在裝飾器中獲取這些元數(shù)據(jù)杀狡,完成對(duì)類(lèi)、類(lèi)的方法等等的修改贰镣,可以在裝飾器中添加元數(shù)據(jù)的支持呜象,比如可以可以在裝飾器工廠(chǎng)函數(shù)以及裝飾器函數(shù)中添加元數(shù)據(jù)支持等。

注解與裝飾器的區(qū)別

雖然語(yǔ)法上很相似碑隆,但在不同的語(yǔ)言中可能使用的是不同的概念:

使用注解(Annotation)的語(yǔ)言:AtScript恭陡、Java、C#(叫 Attribute)上煤。

使用裝飾器(Decorator)的語(yǔ)言:Python休玩、JavaScript/ECMAScript。

從概念上來(lái)說(shuō)劫狠,我們可以很清晰的看出拴疤,注解和裝飾器在語(yǔ)義上沒(méi)有任何共性!

注解和裝飾器可以互相模擬嘉熊,不等同遥赚。 裝飾器可以天生跑在運(yùn)行時(shí),注解還要通過(guò)反射(拿不到類(lèi)型本身)

繼承模式是豐富子元素“內(nèi)涵”的一種重要方式阐肤,不管是繼承接口還是子類(lèi)繼承基類(lèi)凫佛。而裝飾者模式可以在不改變繼承關(guān)系的前提下,包裝先有的模塊孕惜,使其內(nèi)涵更加豐富愧薛,并不會(huì)影響到原來(lái)的功能。與繼承相比衫画,更加的靈活毫炉。

裝飾器最為強(qiáng)大的功能之一是它能夠反射元數(shù)據(jù)(reflect metada)

為什么需要在JavaScript中進(jìn)行反射?

反射用于描述能夠檢查同一系統(tǒng)(或其自身)中的其他代碼的代碼削罩。

JavaScript應(yīng)用程序越來(lái)越大瞄勾,所以需要一些工具(如控件容器的反轉(zhuǎn))和像(運(yùn)行時(shí)類(lèi)型斷言)這樣的功能來(lái)管理這種日益增加的復(fù)雜性。

強(qiáng)大的反射API應(yīng)該允許我們?cè)谶\(yùn)行時(shí)檢查未知對(duì)象并找出有關(guān)它的所有內(nèi)容弥激。我們應(yīng)該能夠找到像這樣的東西:

實(shí)體的名稱(chēng)进陡。

實(shí)體的類(lèi)型。

哪些接口由實(shí)體實(shí)現(xiàn)微服。

實(shí)體屬性的名稱(chēng)和類(lèi)型趾疚。

實(shí)體的構(gòu)造函數(shù)參數(shù)的名稱(chēng)和類(lèi)型

在JavaScript中,我們可以使用Object.getOwnPropertyDescriptor()或Object.keys()等函數(shù)來(lái)查找有關(guān)實(shí)體的一些信息,但我們需要反思來(lái)實(shí)現(xiàn)更強(qiáng)大的開(kāi)發(fā)工具糙麦。

但是辛孵,事情即將發(fā)生變化,因?yàn)門(mén)ypeScript開(kāi)始支持一些Reflection功能赡磅。但實(shí)際上它們只是一些 JavaScript 函數(shù)魄缚,能夠幫助我們來(lái)注釋代碼或者是修改代碼的行為——這種做法我們通常稱(chēng)為元編程。

TypeScript?裝飾器

裝飾器能夠很好的抽象代碼仆邓,它們最適合用來(lái)包裝可能會(huì)多處復(fù)用的邏輯鲜滩。

五種裝飾器的方法

類(lèi)聲明

屬性

方法

參數(shù)

accessor

類(lèi)裝飾器 Class Decorator

類(lèi)裝飾器使得開(kāi)發(fā)者能夠攔截類(lèi)的構(gòu)造方法 constructor

注意:當(dāng)我們聲明一個(gè)類(lèi)時(shí)节值,裝飾器就會(huì)被調(diào)用徙硅,而不是等到類(lèi)實(shí)例化的時(shí)候。

當(dāng)你裝飾一個(gè)類(lèi)的時(shí)候搞疗,裝飾器并不會(huì)對(duì)該類(lèi)的子類(lèi)生效嗓蘑,讓我們來(lái)凍結(jié)一個(gè)類(lèi)來(lái)徹底避免別的程序員不小心忘了這個(gè)特性。

@Frozen

class?IceCream?{}

function?Frozen(constructor:?Function)?{

??Object.freeze(constructor);

??Object.freeze(constructor.prototype);

}

console.log(Object.isFrozen(IceCream));?//?true

class?FroYo?extends?IceCream?{}?//?報(bào)錯(cuò)匿乃,類(lèi)不能被擴(kuò)展

當(dāng)裝飾函數(shù)直接修飾類(lèi)的時(shí)候桩皿,裝飾函數(shù)接受唯一的參數(shù)constructor,這個(gè)參數(shù)就是該被修飾類(lèi)本身幢炸。

此外泄隔,在修飾類(lèi)的時(shí)候,如果裝飾函數(shù)有返回值宛徊,該返回值會(huì)重新定義這個(gè)類(lèi)佛嬉,也就是說(shuō)當(dāng)裝飾函數(shù)有返回值時(shí),其實(shí)是生成了一個(gè)新類(lèi)闸天,該新類(lèi)通過(guò)返回值來(lái)定義暖呕。

方法裝飾器 Method Decorator

方法裝飾器來(lái)覆寫(xiě)一個(gè)方法,改變它的執(zhí)行流程苞氮,以及在它執(zhí)行前后額外運(yùn)行一些代碼湾揽。

下面這個(gè)例子會(huì)在執(zhí)行真正的代碼之前彈出一個(gè)確認(rèn)框。如果用戶(hù)點(diǎn)擊了取消笼吟,方法就會(huì)被跳過(guò)库物。注意,這里我們裝飾了一個(gè)方法兩次贷帮,這兩個(gè)裝飾器會(huì)從上到下地執(zhí)行艳狐。

function?log(target,?key,?descriptor)?{}

class?P?{

????@log

????foo()?{

??????console.log('Do?something');

????}

}

對(duì)于類(lèi)的函數(shù)的裝飾器函數(shù),依次接受的參數(shù)為:

target:如果修飾的是類(lèi)的實(shí)例函數(shù)皿桑,那么target就是類(lèi)的原型。如果修飾的是類(lèi)的靜態(tài)函數(shù),那么target就是類(lèi)本身诲侮。

key: 該函數(shù)的函數(shù)名镀虐。

descriptor:該函數(shù)的描述屬性,比如 configurable沟绪、value刮便、enumerable等。

屬性裝飾器 Property Decorator

屬性裝飾器極其有用绽慈,因?yàn)樗?b>可以監(jiān)聽(tīng)對(duì)象狀態(tài)的變化恨旱。

為了充分了解接下來(lái)這個(gè)例子,建議你先熟悉一下 JavaScript 的屬性描述符(PropertyDescriptor)坝疼。

function?foo(target,name){}

class?P{

???@foo

???name?=?'Jony'

}

這里對(duì)于類(lèi)的屬性的裝飾器函數(shù)接受兩個(gè)參數(shù)搜贤,

第一個(gè)參數(shù):

對(duì)于靜態(tài)屬性而言,是類(lèi)本身

對(duì)于實(shí)例屬性而言钝凶,是類(lèi)的原型仪芒,

第二個(gè)參數(shù):所指屬性的名字。

類(lèi)函數(shù)參數(shù)的裝飾器

類(lèi)函數(shù)的參數(shù)裝飾器可以修飾類(lèi)的構(gòu)建函數(shù)中的參數(shù)耕陷,以及類(lèi)中其他普通函數(shù)中的參數(shù)掂名。該裝飾器在類(lèi)的方法被調(diào)用的時(shí)候執(zhí)行

function?foo(target,key,index){}

class?P{

???test(@foo?a){

???}

}

類(lèi)函數(shù)參數(shù)的裝飾器函數(shù)接受三個(gè)參數(shù)

target: 類(lèi)本身

key:該參數(shù)所在的函數(shù)的函數(shù)名

index: 該參數(shù)在函數(shù)參數(shù)列表中的索引值

裝飾器可以起到分離復(fù)雜邏輯的功能哟沫,且使用上極其簡(jiǎn)單方便饺蔑。與繼承相比,也更加靈活嗜诀,可以從裝飾類(lèi)猾警,到裝飾類(lèi)函數(shù)的參數(shù),可以說(shuō)武裝到了“牙齒”裹虫。

Typescript中的元數(shù)據(jù)操作

可以通過(guò)reflect-metadata包來(lái)實(shí)現(xiàn)對(duì)于元數(shù)據(jù)的操作肿嘲。首先我們來(lái)看reflect-metadata的使用,首先定義使用元數(shù)據(jù)的函數(shù):

const?formatMetadataKey?=?Symbol("format");

function?format(formatString:?string)?{

????return?Reflect.metadata(formatMetadataKey,?formatString);

}

function?getFormat(target:?any,?propertyKey:?string)?{

????return?Reflect.getMetadata(formatMetadataKey,?target,?propertyKey);

}

這里的format可以作為裝飾器函數(shù)的工廠(chǎng)函數(shù)筑公,因?yàn)閒ormat函數(shù)返回的是一個(gè)裝飾器函數(shù)雳窟,上述的方法定義了元數(shù)據(jù)Sysmbol("format"),用Sysmbol的原因是為了防止元數(shù)據(jù)中的字段重復(fù),而format定義了取元數(shù)據(jù)中相應(yīng)字段的功能匣屡。

接著我們來(lái)在類(lèi)中使用相應(yīng)的元數(shù)據(jù):

class?Greeter?{

????@format("Hello,?%s")

????name:?string;

????constructor(name:?string)?{

????????this.name?=?message;

????}

????sayHello()?{

????????let?formatString?=?getFormat(this,?"name");

????????return?formatString.replace("%s",?this.name);

????}

}

const?g?=?new?Greeter("Jony");

console.log(g.sayHello());

在上述中封救,我們?cè)趎ame屬性的裝飾器工廠(chǎng)函數(shù),執(zhí)行@format("Hello, %s")捣作,返回一個(gè)裝飾器函數(shù)誉结,且該裝飾器函數(shù)修飾了Greeter類(lèi)的name屬性,將“name”屬性的值寫(xiě)入為"Hello, %s"券躁。

然后再sayHello方法中惩坑,通過(guò)getFormat(this,"name")取到formatString為“Hello,%s”.

參考列表:

TypeScript中的裝飾器&元數(shù)據(jù)反射:從新手到專(zhuān)家四?https://zhuanlan.zhihu.com/p/42220487

理解 TypeScript 裝飾器?https://zhuanlan.zhihu.com/p/65764702

【認(rèn)真臉】注解與裝飾器的點(diǎn)點(diǎn)滴滴https://zhuanlan.zhihu.com/p/22277764

聊聊Typescript中的設(shè)計(jì)模式——裝飾器篇(decorators)?https://github.com/forthealllight/blog/issues/33

轉(zhuǎn)載本站文章《從java注解漫談到typescript裝飾器——注解與裝飾器》,

請(qǐng)注明出處:https://www.zhoulujun.cn/html/webfront/ECMAScript/typescript/2020_0721_8528.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掉盅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子以舒,更是在濱河造成了極大的恐慌趾痘,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔓钟,死亡現(xiàn)場(chǎng)離奇詭異永票,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)滥沫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)侣集,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人兰绣,你說(shuō)我怎么就攤上這事世分。” “怎么了狭魂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵罚攀,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我雌澄,道長(zhǎng)陡鹃,這世上最難降的妖魔是什么宴抚? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上潭苞,老公的妹妹穿的比我還像新娘表鳍。我一直安慰自己蝌诡,他們只是感情好矗晃,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著畦浓,像睡著了一般痹束。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上讶请,一...
    開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
  • 那天祷嘶,我揣著相機(jī)與錄音,去河邊找鬼夺溢。 笑死论巍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的风响。 我是一名探鬼主播嘉汰,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼状勤!你這毒婦竟也來(lái)了鞋怀?” 一聲冷哼從身側(cè)響起双泪,我...
    開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎接箫,沒(méi)想到半個(gè)月后攒读,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辛友,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了剪返。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片废累。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖脱盲,靈堂內(nèi)的尸體忽然破棺而出邑滨,到底是詐尸還是另有隱情,我是刑警寧澤钱反,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布掖看,位于F島的核電站,受9級(jí)特大地震影響面哥,放射性物質(zhì)發(fā)生泄漏哎壳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一尚卫、第九天 我趴在偏房一處隱蔽的房頂上張望归榕。 院中可真熱鬧,春花似錦吱涉、人聲如沸刹泄。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)特石。三九已至,卻和暖如春鳖链,著一層夾襖步出監(jiān)牢的瞬間姆蘸,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工撒轮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乞旦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓题山,卻偏偏與公主長(zhǎng)得像兰粉,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子顶瞳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 先看一段代碼 這是一段TypeScript上 koa 路由類(lèi)的寫(xiě)法玖姑,注意到在其中愕秫,使用了@Paht @Get的寫(xiě)法...
    Mr_Treasure閱讀 17,686評(píng)論 9 16
  • 參數(shù)裝飾器 參數(shù)裝飾器聲明在一個(gè)參數(shù)聲明之前(緊靠著參數(shù)聲明)。 參數(shù)裝飾器應(yīng)用于類(lèi)構(gòu)造函數(shù)或方法聲明焰络。 參數(shù)裝飾...
    2o壹9閱讀 853評(píng)論 1 49
  • 大綱 本章主要講解一些ts的高級(jí)用法戴甩,涉及以下內(nèi)容: 類(lèi)型斷言與類(lèi)型守衛(wèi) in關(guān)鍵詞和is關(guān)鍵詞 類(lèi)型結(jié)構(gòu) 裝飾器...
    aliensq閱讀 477評(píng)論 0 1
  • 訪(fǎng)問(wèn)器裝飾器 訪(fǎng)問(wèn)器裝飾器聲明在一個(gè)訪(fǎng)問(wèn)器的聲明之前(緊靠著訪(fǎng)問(wèn)器聲明)。 訪(fǎng)問(wèn)器裝飾器應(yīng)用于訪(fǎng)問(wèn)器的 屬性描述符...
    2o壹9閱讀 1,046評(píng)論 1 49
  • 回顧類(lèi)的屬性 回顧面向?qū)ο笊帘耍?lèi)中的屬性分為實(shí)例屬性和靜態(tài)屬性甜孤,實(shí)例屬性屬于實(shí)例化后的對(duì)象,靜態(tài)屬性屬于類(lèi)本身 在類(lèi)...
    Rollover閱讀 2,316評(píng)論 0 0