裝飾器本身是一個函數(shù)少办,因?yàn)檠b飾器是對類進(jìn)行修飾的,所以是類的裝飾器券躁,裝飾器通過@符號來使用艾扮。
裝飾器接受的參數(shù)是一個類的構(gòu)造函數(shù)
function testDecorator (constructor: any) {
constructor.prototype.getName = () => {
console.log('weiyang');
};
}
@testDecorator(true)
class Test{ }
(test as any).getName()
裝飾器的運(yùn)行時機(jī)是類創(chuàng)建好后艰毒,立即執(zhí)行筐高,而不是實(shí)例化一個類的時候。
可以有多個裝飾器丑瞧,裝飾器執(zhí)行順序是從下到上柑土,從右到左。
function testDecorator1 (constructor: any) {
constructor.prototype.getName = () => {
console.log('yang1');
};
}
function testDecorator2 (constructor: any) {
constructor.prototype.getName = () => {
console.log('yang2');
};
}
@testDecorator1 @testDecorator2 class Test{ }
對裝飾器做工廠模式的包裝绊汹,就可以做一些參數(shù)上的判斷了
function testDecorator(flag: boolean) {
if (flag) {
return function (constructor: any) {
constructor.prototype.getName = () => {
console.log('weiyang');
};
}
} else {
return function (constructor: any) {}
}
}
@testDecorator(true)
class Test{ }
const test = new Test();
(test as any).getName()
上邊裝飾器的寫法冰单,我們通過test .getName()
的時候,不會主動提示灸促。所以不是一種特別正規(guī)的裝飾器的寫法县貌。正規(guī)的怎么寫呢?
function testDecorator<T extends new (...args: any[]) => any>(constructor: T) {
// 這里改造的構(gòu)造函數(shù)后執(zhí)行
return class extends constructor{
name = 'lee';
getName() {
return this.name;
}
}
}
@testDecorator
class Test{
name: string;
// 這個構(gòu)造函數(shù)先執(zhí)行
constructor(name: string) {
this.name = name;
}
}
const test = new Test('yang');
console.log((test as any).getName()); // 沒有改造構(gòu)造函數(shù)之前返回 {name:'yang'},改造之后返回 {name:'lee'}
- <T extends new (...args:any[]) => any>解析一下這個泛型提佣,泛型T繼承了自一個構(gòu)造函數(shù)涎劈,這個構(gòu)造函數(shù),接受任意類型的數(shù)據(jù)組成的數(shù)組作為參數(shù)典鸡,這個構(gòu)造函數(shù)返回任意類型的數(shù)據(jù)
- class extends constructor{}這里是對構(gòu)造函數(shù)進(jìn)行改寫被廓。這個改寫的執(zhí)行是在定義類的構(gòu)造函數(shù)之后執(zhí)行的。
- (constructor: T) 這里的意思是 constructor的類型就是一個泛型萝玷,這個泛型 T的意思是嫁乘,可以通過實(shí)例化創(chuàng)建出一個類,這個類應(yīng)該包含new (...args:any[]) => any這樣的構(gòu)造函數(shù)
經(jīng)過上邊的寫法后球碉,我們?nèi)ネㄟ^test調(diào)用getName方法還是會報錯蜓斧,除非是 test as any才可以。原因是 我們定義類test的時候睁冬,并沒有直接定義getName方法挎春,而getName是testDecorator裝飾器偷偷的裝飾的時候加進(jìn)來的,這個時候typescript是不知道加了這個方法的豆拨,要解決這個問題直奋,需要工廠模式
。
function testDecoratorFactory() {
return function <T extends new (...args: any[]) => any>(constructor: T) {
// 這里改造的構(gòu)造函數(shù)后執(zhí)行
return class extends constructor{
name = 'lee';
getName() {
return this.name;
}
}
}
}
// 這個時候testDecoratorFactory不是當(dāng)成一個裝飾器來用施禾,而是當(dāng)成一個函數(shù)來用
// testDecoratorFactory()函數(shù)執(zhí)行脚线,返回一個裝飾器
// 裝飾器后邊再跟(class {}),表示裝飾器裝飾的是一個沒用名字的class,這個class就多出一個getName的方法了
// 修飾完成之后弥搞,把返回的東西復(fù)制給 Test
const Test = testDecoratorFactory()(class {
name: string;
constructor(name: string) {
this.name = name;
}
})
// 這里再去new 的Test是裝飾器裝飾過后的 class
// 所以實(shí)例 test就可以訪問到getName了
const test = new Test('yang');
console.log(test.getName());