【前端】你好,我叫TypeScript (五)裝飾器
1.什么是裝飾器
裝飾器是一種特殊類型的聲明,它能夠被附加到類聲明,方法,訪問符,屬性和參數上。
- 裝飾器是一個表達式
- 表達式被執行后,返回一個函數
- 函數的輸入參數為:target,name和descriptor
- 執行函數后,可能返回descriptor對象,用于配置target對象
裝飾器使用@expression形式,expression求值后必須返回一個函數,他會在運行時被調用,被裝飾的聲明信息作為參數傳入。
例如:
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- // 使用裝飾器
- class Boat{
- color: string = "yellow";
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @testDecorator
- pilot(): void{
- console.log("swish");
- }
- }
- // 實例化
- const boat = new Boat();
- boat.pilot();
- console.log(boat.formattedColor);
運行得到:
- Target: {}
- key: pilot
- swish
- this boat color is yellow
2.裝飾器分類
裝飾器根據其所裝飾的類型分為以下一種:
- 類裝飾器
- 屬性裝飾器
- 方法裝飾器
- 參數裝飾器
若要啟用實驗性的裝飾器特性,你必須在命令行或tsconfig.json里啟用experimentalDecorators編譯器選項:
命令行:
- tsc --target ES5 --experimentalDecorators
tsconfig.json:
- {
- "compilerOptions": {
- "target": "ES5",
- "experimentalDecorators": true
- }
- }
2.1 類裝飾器
類裝飾器用于類構造函數,進行監聽、修改或替換類定義,在類聲明之前進行聲明(緊挨著類聲明)。
切記:
- 類裝飾器不能用在聲明文件中(.d.ts),也不能用在任何外部上下文中。
- 類裝飾器表達式會在運行時當作函數被調用,類的構造函數作為其唯一的參數。
- 如果類裝飾器返回一個值,它會使用提供的構造函數來替換類的聲明。
- 如果你要返回一個新的構造函數,你必須注意處理好原來的原型鏈。在運行時的裝飾器調用邏輯中不會為你做這些。
類裝飾器聲明:
- declare type ClassDecorator = <TFunction extends Function>(
- target: TFunction
- )=>TFunction | void;
類裝飾器顧名思義,就是⽤來裝飾類的。它接收⼀個參數:
- target: TFunction - 被裝飾的類
栗子:
- // 類裝飾器
- function classDecorator(constructor: typeof Boat){
- console.log(constructor);
- }
- // 使用類裝飾器
- @classDecorator
- class Boat{
- }
運行結果:
- [class Boat]
2.2 方法裝飾器
方法裝飾器用于方法的屬性描述符,可以進行監聽、修改或替換方法定義,在待修飾方法聲明前進行聲明。方法裝飾器不能用在聲明文件(.d.ts),重載或者任何外部上下文中。
方法裝飾器表達式會在運行時當作函數被調用,傳入下列3個參數:
- target:被裝飾的類
- key: 方法名
- descriptor: 屬性描述符
「注意:如果代碼輸出目標版本小于ES5,屬性描述符將會是undefined。」
如果方法裝飾器返回一個值,它會被用作方法的屬性描述符。
舉個栗子:
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- function logError(errorMessage: string){
- return function(target: any, key: string, desc: PropertyDescriptor){
- const method = desc.value;
- desc.value = function(){
- try {
- method();
- }catch(err){
- console.log(errorMessage);
- }
- }
- }
- }
- // 使用裝飾器
- class Boat{
- color: string = "yellow";
- @testDecorator
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @logError("Oops boat was sunk in ocean")
- pilot(): void{
- throw new Error()
- console.log("swish");
- }
- }
- // 實例化
- const boat = new Boat();
- boat.pilot();
運行得到:
- Target: {}
- key: formattedColor
- Oops boat was sunk in ocean
2.3 屬性裝飾器
屬性裝飾器屬性描述符只能用來監視類中是否聲明了某個名字的屬性,在屬性聲明前進行聲明。
屬性裝飾器表達式會在運行時當做函數進行調用,傳入兩個參數:
- target: 被裝飾的類
- key: 被裝飾類的屬性名字
注意:屬性描述符不作為參數傳入屬性裝飾器。因為目前還沒有辦法在定義一個原型對象時描述一個實例屬性,并且沒有辦法進行建議監聽或修改一個屬性的初始化方法。
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- function logError(errorMessage: string){
- return function(target: any, key: string, desc: PropertyDescriptor){
- const method = desc.value;
- desc.value = function(){
- try {
- method();
- }catch(err){
- console.log(errorMessage);
- }
- }
- }
- }
- // 使用裝飾器
- class Boat{
- @testDecorator
- color: string = "yellow";
- // @testDecorator
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @logError("Oops boat was sunk in ocean")
- pilot(): void{
- throw new Error()
- console.log("swish");
- }
- }
運行結果:
- Target: {}
- key: color
2.4 參數裝飾器
參數裝飾器用于類構造函數或方法聲明。接收三個參數:
- target: 被裝飾的類
- key:方法名
- index:方法中的參數索引值
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- function logError(errorMessage: string){
- return function(target: any, key: string, desc: PropertyDescriptor){
- const method = desc.value;
- desc.value = function(){
- try {
- method();
- }catch(err){
- console.log(errorMessage);
- }
- }
- }
- }
- // 參數裝飾器
- function parameterDecorator(target: any, key: string, index: number){
- console.log(key, index);
- }
- // 使用裝飾器
- class Boat{
- @testDecorator
- color: string = "yellow";
- // @testDecorator
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @logError("Oops boat was sunk in ocean")
- pilot(): void{
- throw new Error()
- console.log("swish");
- }
- fast(
- @parameterDecorator speed: string,
- @parameterDecorator generateWake: boolean
- ): void{
- if(speed === "fast"){
- console.log("swish");
- }else{
- console.log("nothing");
- }
- }
- }
運行結果:
- Target: {}
- key: color
- fast 1
- fast 0
小結
我們看到裝飾器很方便為我們結果了許多問題。裝飾器根據其裝飾的對象不同,分為:類裝飾器、屬性裝飾器、方法裝飾器、參數裝飾器。