摘要:本文從裝飾模式出發,聊聊中的裝飾器和注解。該函數的函數名。不提供元數據的支持。中的元數據操作可以通過包來實現對于元數據的操作。
??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經常看到類似于java spring中注解的寫法。本文從裝飾模式出發,聊聊Typescipt中的裝飾器和注解。
什么是裝飾者模式
Typescript中的裝飾器
Typescript中的注解
總結
原文地址:https://github.com/forthealll...
歡迎star
一、什么是裝飾者模式??最近在看nestjs等支持Typescript的node框架,經常看到這樣一種寫法:
import { Controller, Get } from "@nestjs/common"; @Controller("cats") export class CatsController { @Get() findAll() { return "This action returns all cats"; } }
??上述代碼定義了一個處理url為“/cats”的控制器,該控制器對于url為“/cats”的get方法執行findAll()函數,返回相應的字符串。
??在上述的代碼中,用@Controller("cats")修飾CatsController類,通過@Get來修飾類中的findAll方法,這就是典型的裝飾者模式。通過@Controller("cats")和@Get修飾后的類CatsController,簡單來說,就是擁有了豐富的“內涵”。
下面看看具體裝飾者模式的定義:
我們知道繼承模式是豐富子元素“內涵”的一種重要方式,不管是繼承接口還是子類繼承基類。而裝飾者模式可以在不改變繼承關系的前提下,包裝先有的模塊,使其內涵更加豐富,并不會影響到原來的功能。與繼承相比,更加的靈活。
javascript中的裝飾器處于建議征集的第二階段,通過babel和Typescrit都可以實現裝飾器的語法。
二、Typescript中的裝飾器Typescript中的裝飾器與類相關,分別可以修飾類的實例函數和靜態函數、類本身、類的屬性、類中函數的參數以及類的set/get存取器,下面來意義介紹。
(1)、類方法的裝飾器下面來介紹一下用裝飾器來修飾函數,首先來看一個例子:
let temple; function log(target, key, descriptor) { console.log(`${key} was called!`); temple = target; } class P { @log foo() { console.log("Do something"); } } const p = new P() p.foo() console.log(P.prototype === temple) //true
上述是實例方法foo中我們用log函數修飾,log函數接受三個參數,通過P.prototype === temple(target)可以判斷,在類的實例函數的裝飾器函數第一個參數為類的原型,第二個參數為函數名本身,第三個參數為該函數的描述屬性。
具體總結如下,對于類的函數的裝飾器函數,依次接受的參數為:
target:如果修飾的是類的實例函數,那么target就是類的原型。如果修飾的是類的靜態函數,那么target就是類本身。
key: 該函數的函數名。
descriptor:該函數的描述屬性,比如 configurable、value、enumerable等。
從上述的例子中我們可以看到,用裝飾器來修飾相應的類的函數十分方便:
@log foo() { ... }(2)、類的裝飾器
裝飾函數也可以直接修飾類:
let temple function foo(target){ console.log(target); temple = target } @foo class P{ constructor(){ } } const p = new P(); temple === P //true
當裝飾函數直接修飾類的時候,裝飾函數接受唯一的參數,這個參數就是該被修飾類本身。上述的例子中,輸出的target就是類P的本身。
此外,在修飾類的時候,如果裝飾函數有返回值,該返回值會重新定義這個類,也就是說當裝飾函數有返回值時,其實是生成了一個新類,該新類通過返回值來定義。
舉例來說:
function foo(target){ return class extends target{ name = "Jony"; sayHello(){ console.log("Hello "+ this.name) } } } @foo class P{ constructor(){ } } const p = new P(); p.sayHello(); // 會輸出Hello Jony
上面的例子可以看到,當裝飾函數foo有返回值時,實際上P類已經被返回值所代表的新類所代替,因此P的實例p擁有sayHello方法。
(3)、類的屬性的裝飾器下面我們來看類的屬性的裝飾器,裝飾函數修飾類的屬性時,在類實例化的時候調用屬性的裝飾函數,舉例來說:
function foo(target,name){ console.log("target is",target); console.log("name is",name) } class P{ @foo name = "Jony" } const p = new P(); //會依次輸出 target is f P() name is Jony
這里對于類的屬性的裝飾器函數接受兩個參數,對于靜態屬性而言,第一個參數是類本身,對于實例屬性而言,第一個參數是類的原型,第二個參數是指屬性的名字。
(4)、類函數參數的裝飾器接著來看類函數參數的裝飾器,類函數的參數裝飾器可以修飾類的構建函數中的參數,以及類中其他普通函數中的參數。該裝飾器在類的方法被調用的時候執行,下面來看實例:
function foo(target,key,index){ console.log("target is",target); console.log("key is",key); console.log("index is",index) } class P{ test(@foo a){ } } const p = new P(); p.test("Hello Jony") // 依次輸出 f P() , test , 0
類函數參數的裝飾器函數接受三個參數,依次為類本身,類中該被修飾的函數本身,以及被修飾的參數在參數列表中的索引值。上述的例子中,會依次輸出 f P() 、test和0。再次明確一下修飾函數參數的裝飾器函數中的參數含義:
target: 類本身
key:該參數所在的函數的函數名
index: 該參數在函數參數列表中的索引值
從上面的Typescrit中在基類中常用的裝飾器后,我們發現:
裝飾器可以起到分離復雜邏輯的功能,且使用上極其簡單方便。與繼承相比,也更加靈活,可以從裝飾類,到裝飾類函數的參數,可以說武裝到了“牙齒”。
三、Typescript中的注解在了解了Typescrit中的裝飾器之后,接著我們來看Typescrit中的注解。
什么是注解,所謂注解的定義就是:
為相應的類附加元數據支持。
所謂元數據可以簡單的解釋,就是修飾數據的數據,比如一個人有name,age等數據屬性,那么name和age這些字段就是為了修飾數據的數據,可以簡單的稱為元數據。
元數據簡單來說就是可以修飾某些數據的字段。下面給出裝飾器和注解的解釋和區別:
裝飾器:定義劫持,可以對類,類的方法,類的屬性以及類的方法的入參進行修改。不提供元數據的支持。
注解:僅提供元數據的支持。
兩者之間的聯系:
通過注解添加元數據,然后在裝飾器中獲取這些元數據,完成對類、類的方法等等的修改,可以在裝飾器中添加元數據的支持,比如可以可以在裝飾器工廠函數以及裝飾器函數中添加元數據支持等。
(1)、Typescript中的元數據操作可以通過reflect-metadata包來實現對于元數據的操作。首先我們來看reflect-metadata的使用,首先定義使用元數據的函數:
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可以作為裝飾器函數的工廠函數,因為format函數返回的是一個裝飾器函數,上述的方法定義了元數據Sysmbol("format"),用Sysmbol的原因是為了防止元數據中的字段重復,而format定義了取元數據中相應字段的功能。
接著我們來在類中使用相應的元數據:
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());
在上述中,我們在name屬性的裝飾器工廠函數,執行@format("Hello, %s"),返回一個裝飾器函數,且該裝飾器函數修飾了Greeter類的name屬性,將“name”屬性的值寫入為"Hello, %s"。
然后再sayHello方法中,通過getFormat(this,"name")取到formatString為“Hello,%s”.
四、總結通過裝飾器,可以方便的修飾類,以及類的方法,類的屬性等,相比于繼承而言更加靈活,此外,通過注解的方法,可以在Typescript中引入元數據,實現元編程等。特別是在angularjs、nestjs中,大量使用了注解,特別是nestjs構建了類似于java springMVC式的web框架。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100093.html
摘要:裝飾者模式裝飾者模式就是動態的給類或對象增加功能的設計模式。下的實現里的裝飾器目前處在建議征集的第二階段,不被瀏覽器所支持,如果想要提前使用這個新特性就需要,等工具進行轉譯。這里介紹下的用法。 1.1、裝飾者模式 裝飾者模式就是動態的給類或對象增加功能的設計模式。在程序運行時動態的給一個具備基礎功能的類或對象添加新的功能,并且不會改變會破壞基礎類和對象的功能。先提煉出產品的最小可用產品...
摘要:使用裝飾器的方法很簡單在裝飾器名前加字符,寫在想要裝飾的方法上,類似寫注釋的方式裝飾器實際上是一個函數,入參為所裝飾的方法,返回值為裝飾后的方法。經過裝飾過的方法,它依然按照原來的方式執行,只是額外執行了附件的裝飾器函數的功能。 讓我來深入地了解一下TypeScript對于裝飾器模式的實現,以及反射與依賴注入等相關特性。 在Typescript的源代碼中,可以看到裝飾器能用來修飾cla...
摘要:新項目起手式最后更新于,技術文具有時效性,請知悉我知道你們早就想用上強類型了還有后續進階篇安裝安裝依賴配置添加添加讓識別改造文件什么是是的強類型版本。是的超集,這意味著他支持所有的語法。與此同時,也是的超集,的也宣布采用進行開發。 vue + typescript 新項目起手式 最后更新于2018-06-30,技術文具有時效性,請知悉 我知道你們早就想用上 vue + ts 強類型...
摘要:第二部分源碼解析接下是應用多個第二部分對于一個方法應用了多個,比如會編譯為在第二部分的源碼中,執行了和操作,由此我們也可以發現,如果同一個方法有多個裝飾器,會由內向外執行。有了裝飾器,就可以改寫上面的代碼。 Decorator 裝飾器主要用于: 裝飾類 裝飾方法或屬性 裝飾類 @annotation class MyClass { } function annotation(ta...
閱讀 2609·2021-11-17 17:00
閱讀 1863·2021-10-11 10:57
閱讀 3716·2021-09-09 11:33
閱讀 911·2021-09-09 09:33
閱讀 3550·2019-08-30 14:20
閱讀 3311·2019-08-29 11:25
閱讀 2796·2019-08-26 13:48
閱讀 734·2019-08-26 11:52