假設(shè)我有一個(gè)汽車工廠拴魄,每天都在生產(chǎn)汽車汛骂,他們都有統(tǒng)一的名字和價(jià)格,都可以在公路上開溯街,那么诱桂,我們很容易寫出如下代碼:
PS: 如果沒有搭建 TypeScript 的開發(fā)環(huán)境,請(qǐng)看這里
class Car {
private name: string;
private price: number;
constructor(name: string, price: number) {
this.name = name;
this.price = price;
}
getName() {
console.log(this.name);
}
getPrice() {
console.log(this.price);
}
drive() {
console.log("drive");
}
}
const toyota: Car = new Car("toyota", 175000);
toyota.getName();
toyota.getPrice();
toyota.drive();
那么呈昔,當(dāng)我需要為每一輛出廠的車都安裝行車記錄儀器時(shí)挥等,那么,我們可能會(huì)修改為如下代碼:
class Car {
private name: string;
private price: number;
constructor(name: string, price: number) {
this.name = name;
this.price = price;
}
getName() {
console.log(this.name);
}
getPrice() {
console.log(this.price);
}
drive() {
console.log("drive");
}
// 添加行車記錄儀
driveRecorder() {
console.log("driveRecorder");
}
}
const toyota: Car = new Car("toyota", 175000);
toyota.getName();
toyota.getPrice();
toyota.drive();
toyota.driveRecorder();
上面代碼能正確執(zhí)行堤尾,我們也為每輛出廠的車添加上了行車記錄儀肝劲。那么,現(xiàn)實(shí)中行車記錄儀一般都是郭宝,客戶買了車后才會(huì)去安裝的辞槐,也就是說(shuō),車輛在設(shè)計(jì)的時(shí)候不會(huì)考慮把一些非必要的配件都設(shè)計(jì)上粘室,只會(huì)留出空間榄檬,讓客戶去安裝。同理衔统,從代碼的角度 driveRecorder 這個(gè)方法不應(yīng)改寫進(jìn) Car 類里邊鹿榜,它不是在類本身的東西先朦,是之后加上的,上面的代碼顯然破壞了類的設(shè)計(jì)犬缨,那么我們可以把 driveRecorder 添加到類的外面喳魏,也就是把它做成一個(gè)裝飾器,裝飾我們的類怀薛,那么我們的代碼修改為如下:
function recorder(constructor: any) {
constructor.prototype.driveRecorder = () => {
console.log("driveRecorder");
};
}
@recorder // @recorder 為類的裝飾器
class Car {
private name: string;
private price: number;
constructor(name: string, price: number) {
this.name = name;
this.price = price;
}
getName() {
console.log(this.name);
}
getPrice() {
console.log(this.price);
}
drive() {
console.log("drive");
}
}
const toyota: Car = new Car("toyota", 175000);
toyota.getName();
toyota.getPrice();
toyota.drive();
toyota.driveRecorder();
那么刺彩,如果您直接抄上面的代碼,可能會(huì)得到如下兩個(gè)報(bào)錯(cuò)提示:
1.裝飾器語(yǔ)法報(bào)錯(cuò)
通過提示我們知道枝恋,TypeScript的裝飾器在ES語(yǔ)法中屬于一個(gè)實(shí)驗(yàn)性值的語(yǔ)法创倔,故在VSCode中會(huì)報(bào)錯(cuò),如果要使用裝飾器
則需要把tsconfig.json的'experimentalDecorators'的注釋打開才能解除警報(bào)焚碌,如下圖
2.實(shí)例調(diào)用裝飾器方法報(bào)錯(cuò)
關(guān)于這個(gè)錯(cuò)誤畦攘,我們看下裝飾器
function recorder(constructor: any) {
constructor.prototype.driveRecorder = () => {
console.log("driveRecorder");
};
}
在 TypeScript 的類裝飾器中,裝飾器是一個(gè)函數(shù)十电,那么它的參數(shù)就是這個(gè)類知押,這里的 constructor 就是我們傳入的 Car 類,我們用原型的方法把 driveRecorder 掛載到 constructor 而 constructor 的類型聲明為 any鹃骂,toyota 的類型為 Car台盯,兩個(gè)類型不一樣,所以找不該 driveRecorder 方法報(bào)錯(cuò)畏线,這里我們就臨時(shí)改一下調(diào)用的方式(把 toyota 的類型臨時(shí)改成any):
(toyota as any).driveRecorder();
那么報(bào)錯(cuò)沒了静盅,我們運(yùn)行下代碼,結(jié)果是對(duì)的
回過頭來(lái)看裝飾器和原來(lái)在類中的修改寝殴,執(zhí)行的結(jié)果是一樣的蒿叠,但編程的思想?yún)s不一樣,直接在類中修改看似很方便蚣常,也是我們最容易想到的一個(gè)方式市咽,但這只是我們?cè)谧钍孢m的環(huán)境下想到的,有可能史隆,這個(gè)類不是我們寫魂务,是別人寫的,那么非常不推薦大家去修改別人的代碼泌射,這里推薦使用裝飾器,直接在別人寫好的類上面加上鬓照,不會(huì)破壞別人的代碼
原文鏈接