TypeScript入門筆記(五)

上篇。html

這篇主要記錄TypeScript中的幾種裝飾器的概念與用法。裝飾器(Decorators):用一種特性標註的寫法做爲聲明,可以給類,方法,屬性擴展功能,能夠簡單地理解爲是非侵入式的行爲修改。分爲:類裝飾器、方法裝飾器、屬性裝飾器、訪問器裝飾器、參數裝飾器。json

類裝飾器

 1 /**
 2  * 裝飾器(Decorators):用一種特性標註的寫法做爲聲明,可以給類,方法,屬性擴展功能,能夠簡單地理解爲是非侵入式的行爲修改
 3  * 分爲:類裝飾器、方法裝飾器、屬性裝飾器、訪問器裝飾器、參數裝飾器
 4  * 注:在tsconfig.json中將打開 「"experimentalDecorators": true」 以啓用裝飾器功能
 5  */
 6 
 7 /* ****************************類裝飾器******************************* */
 8 //如下這個Person類使用了裝飾器「yasuo」
 9 //@yasuo
10 class Person {
11     roleLine: string | undefined;
12 
13     constructor(readonly name: string, readonly birthDay: Date) {
14         this.roleLine = "Hello everyone"
15     }
16 
17     SayHi(): void {
18         console.log(this.roleLine);
19     }
20 }
21 
22 /**
23  * 裝飾器其實也是一個方法,裝飾器中能夠作的事有三:
24  * (1)作點本身想作的事
25  * (2)擴展屬性或者方法
26  * (3)重載類的構造函數
27  */
28 
29 //參數target便表明Person類(的構造器)
30 function yasuo(target: any) {
31     //(1)只要有類應用了這個裝飾器,便會執行
32     console.log("Follow the wind, but watch your back.")
33 
34     //(2)爲Person類擴展一個Attach的方法
35     target.prototype.Attack = function () {
36         console.log("Hasaki!");
37     }
38 
39     //(3)重載構造函數
40     return class extends target {
41         roleLine: any = "Make it quick."
42     }
43 }
44 //這裏指定爲any類型是爲了防止調用擴展方法Attack時TypeScript編譯器報錯
45 let hero: any = new Person("yasuo", new Date("2013-12-14"));
46 
47 hero.SayHi();   // 控制檯輸出:Make it quick.
48 //hero.Attack()   // 控制檯輸出:Hasaki!
49 
50 
51 /* ****************************裝飾器工廠****************************** */
52 // 帶參數的裝飾器
53 @skin("黑夜使者")
54 class Hero {
55     roleLine: string | undefined;
56 
57     constructor(readonly name: string, readonly birthDay: Date) {
58         this.roleLine = "welcome to LOL"
59     }
60 
61     SayHi(): void {
62         console.log(this.roleLine);
63     }
64 }
65 //定義「裝飾器工廠」
66 function skin(value: string) {      // 這是一個裝飾器工廠
67     return function (target: any) {      //  這是裝飾器
68         let line: string;
69         switch (value) {
70             case "黑夜使者":
71                 line = "我是變革之風"
72                 break;
73             case "猩紅之月":
74                 line = "Hasaki"
75                 break;
76             default:
77                 line = "Attack"
78                 break;
79         }
80 
81         target.prototype.Attack = function () {
82             console.log(line);
83         }
84     }
85 }
86 
87 let h1: any = new Hero("yasuo", new Date("2013-12-14"));
88 h1.Attack();    //控制檯輸出:我是變革之風

屬性裝飾器

 1 /* ****************************屬性裝飾器****************************** */
 2 // 屬性裝飾器接收兩個參數
 3 // 參數一:對於靜態成員是構造器,對於實例成員是類的原型對象
 4 // 參數二:屬性的名稱
 5 
 6 class Hero {
 7 
 8     @lineInjection("Hasaki")    //使用裝飾器爲其賦值
 9     roleLine: string | undefined;
10 
11     constructor(readonly name: string, readonly birthDay: Date) {
12     }
13 
14     SayHi(): void {
15         console.log(this.roleLine);
16     }
17 }
18 
19 //定義一個屬性裝飾器
20 function lineInjection(line: string) {      //裝飾器的參數
21     return function (target: any, prop: any) {
22         target[prop] = line;
23     }
24 }
25 
26 let h1 = new Hero("yasuo", new Date("2013-12-14"));
27 h1.SayHi();     //控制檯輸出:Hasaki

方法裝飾器

 1 /* ****************************方法裝飾器****************************** */
 2 // 用於監視,修改方法,接受3個參數
 3 // 參數一:對於靜態成員是構造器,對於實例成員是類的原型對象
 4 // 參數二:方法的名稱
 5 // 參數三:方法的屬性描述符,其中value屬性就是當前方法的定義
 6 
 7 class Person {
 8     constructor(public firstName: string, public lastName: string) { }
 9 
10     @useFullName
11     public SayHi(): void {
12         console.log(`i am ${this.firstName}`);
13     }
14 }
15 
16 //定義一個方法裝飾器,修改方法,讓其輸出全名
17 function useFullName(
18     target: object,         //參數一:類的原型對象
19     propertyName: string,   //參數二:成員的名稱
20     descriptor: PropertyDescriptor  //參數三:成員的描述信息
21 ): void {
22 
23     //將改寫前的原方法暫存下來
24     const sayLastName: Function = descriptor.value;
25 
26     //改寫方法
27     descriptor.value = function () {
28         //先調用一次原方法
29         sayLastName.call(this);
30         //再輸出一次全名
31         console.log(`${this.firstName} ${this.lastName}`)
32     };
33 }
34 
35 let mj = new Person("bond", "james");
36 
37 mj.SayHi();     //控制檯輸出:i am bond
38                 //bond james

方法參數裝飾器

 1 /* ****************************方法參數裝飾器****************************** */
 2 // 能夠用來監視方法傳入的參數
 3 // 和以前幾個裝飾器相似,接受的參數以下
 4 // 參數一:對於靜態成員是構造器,對於實例成員是類的原型對象
 5 // 參數二:方法的名稱
 6 // 參數三:參數在方法中的位置(index)
 7 
 8 class Greeter {
 9     greeting: string;
10 
11     constructor(message: string) {
12         this.greeting = message;
13     }
14 
15     greet(@log name: string) {
16         return "Hello " + name + ", " + this.greeting;
17     }
18 }
19 
20 function log(
21     target: Object,
22     propertyKey: string,
23     parameterIndex: number) {
24 
25     console.log(target);
26     console.log(propertyKey);
27     console.log(parameterIndex);
28 }

裝飾器的執行順序

若是一個對象中包含多個裝飾器,如函數

1 @f
2 @g
3 class x

那麼他的執行順序是f(g(x)),先執行下面的裝飾器後再執行上面的。ui

若多種裝飾器共存是,其執行順序是:屬性裝飾器 → 方法裝飾器 → 方法參數裝飾器 → 類裝飾器。this

相關文章
相關標籤/搜索