從一個小例子學習Typescript中的裝飾器Decorator

在ECMAScript中,很早就存在關於裝飾器Decorator的提案,但一直沒有作為正式的特性發布到Javascript中。Typescript實現了其中的一種版本,供我們使用和學習。不過沒關係,區別僅僅在於實現的細節,只要我們理解了裝飾器的目的和作用,即使有了新版本的規範,我們也能從容面對。


裝飾器是用來更改Class的行為,通過裝飾器,我們可以改變某個類的屬性、方法、構造函數的參數等等。而裝飾器的本質就是一個函數,我們在使用時,會把類及其屬性傳給該函數,然後在函數內部更改傳入的類或類的方法,即可實現我們的目的。


以常見的函數節流功能為例,可以編寫一個節流裝飾器工廠函數:

<code>function throttle(timeout: number) {
return function (target: any, propertyName: string, descriptor: any) {
const originalValue = descriptor.value;
let enable = true;
return {
...descriptor,
value: function(...args: any[]) {
if (!enable) { return; }
enable = false;
originalValue(args);
setTimeout(() => {
enable = true;
}, timeout);
}
};
};
}/<code>

在上述工廠函數中,我們接收一個參數,來確定節流的時間間隔。然後我們在工廠函數中返回一個函數,該函數就是實際的裝飾器函數。

裝飾器函數接收三個參數:

  • 我們作用的方法所在類的構造函數或者原型(這取決於方法是靜態方法還是實例方法)
  • 方法名
  • 該方法屬性的描述符

然後我們在裝飾器函數中返回了一個描述符對象,重寫了我們將要更改的方法的描述符。我們把描述符的value替換成了我們新寫的具有節流功能的函數。

然後就可以使用這個修飾符了。

<code>class B {
constructor() {}
@throttle(1100)
alert(string: string) {
console.log(new Date().getUTCSeconds());
console.log(string);
}
}
let ab = new B();
setInterval(() => {
ab.alert('報警');
}, 400);/<code>

我們會發現,即使我們設置了每隔400ms打印一次信息,實際上是每隔1100ms才會打印一次。

上述例子可以從這裡運行:https://www.typescriptlang.org/play


分享到:


相關文章: