【前端】你好,我叫TypeScript (五)装饰器

时间:2021-12-21 02:02:59

【前端】你好,我叫TypeScript (五)装饰器

1.什么是装饰器

 

装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性和参数上。

  • 装饰器是一个表达式
  • 表达式被执行后,返回一个函数
  • 函数的输入参数为:target,name和descriptor
  • 执行函数后,可能返回descriptor对象,用于配置target对象

装饰器使用@expression形式,expression求值后必须返回一个函数,他会在运行时被调用,被装饰的声明信息作为参数传入。

例如:

  1. // 定义装饰器 
  2. function testDecorator(target: anykey: string): void { 
  3.   console.log("Target: ", target ); 
  4.   console.log("key: "key); 
  5.  
  6. // 使用装饰器 
  7. class Boat{ 
  8.   color: string = "yellow"
  9.  
  10.   get formattedColor(): string{ 
  11.     return  `this boat color is ${this.color}`; 
  12.      
  13.   } 
  14.    
  15.   @testDecorator 
  16.   pilot(): void{ 
  17.     console.log("swish"); 
  18.      
  19.   } 
  20.  
  21. // 实例化 
  22. const boat = new Boat(); 
  23. boat.pilot(); 
  24. console.log(boat.formattedColor); 

运行得到:

  1. Target:  {} 
  2. key:  pilot 
  3. swish 
  4. this boat color is yellow 

2.装饰器分类

 

装饰器根据其所装饰的类型分为以下一种:

  • 类装饰器
  • 属性装饰器
  • 方法装饰器
  • 参数装饰器

若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项:

命令行:

  1. tsc --target ES5 --experimentalDecorators 

tsconfig.json:

  1.     "compilerOptions": { 
  2.         "target""ES5"
  3.         "experimentalDecorators"true 
  4.     }     

2.1 类装饰器

 

类装饰器用于类构造函数,进行监听、修改或替换类定义,在类声明之前进行声明(紧挨着类声明)。

切记:

  • 类装饰器不能用在声明文件中(.d.ts),也不能用在任何外部上下文中。
  • 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
  • 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
  • 如果你要返回一个新的构造函数,你必须注意处理好原来的原型链。在运行时的装饰器调用逻辑中不会为你做这些。

类装饰器声明:

  1. declare  type ClassDecorator = <TFunction extends Function>( 
  2.   target: TFunction 
  3. )=>TFunction | void; 

类装饰器顾名思义,就是⽤来装饰类的。它接收⼀个参数:

  • target: TFunction - 被装饰的类

栗子:

  1. // 类装饰器 
  2. function classDecorator(constructor: typeof Boat){ 
  3.   console.log(constructor); 
  4.    
  5.  
  6. // 使用类装饰器 
  7. @classDecorator 
  8. class Boat{ 
  9.  

运行结果:

  1. [class Boat] 

2.2 方法装饰器

 

方法装饰器用于方法的属性描述符,可以进行监听、修改或替换方法定义,在待修饰方法声明前进行声明。方法装饰器不能用在声明文件(.d.ts),重载或者任何外部上下文中。

方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

  • target:被装饰的类
  • key: 方法名
  • descriptor: 属性描述符

「注意:如果代码输出目标版本小于ES5,属性描述符将会是undefined。」

如果方法装饰器返回一个值,它会被用作方法的属性描述符。

举个栗子:

  1. // 定义装饰器 
  2. function testDecorator(target: anykey: string): void { 
  3.   console.log("Target: ", target ); 
  4.   console.log("key: "key); 
  5.  
  6. function logError(errorMessage: string){ 
  7.   return function(target: anykey: string, desc: PropertyDescriptor){ 
  8.     const method = desc.value; 
  9.     desc.value = function(){ 
  10.       try { 
  11.         method(); 
  12.       }catch(err){ 
  13.         console.log(errorMessage); 
  14.          
  15.       } 
  16.     } 
  17.   } 
  18.  
  19. // 使用装饰器 
  20. class Boat{ 
  21.   color: string = "yellow"
  22.  
  23.   @testDecorator 
  24.   get formattedColor(): string{ 
  25.     return  `this boat color is ${this.color}`; 
  26.      
  27.   } 
  28.  
  29.   @logError("Oops boat was sunk in ocean"
  30.   pilot(): void{ 
  31.     throw new Error() 
  32.     console.log("swish"); 
  33.      
  34.   } 
  35.  
  36. // 实例化 
  37. const boat = new Boat(); 
  38. boat.pilot(); 

运行得到:

  1. Target:  {} 
  2. key:  formattedColor 
  3. Oops boat was sunk in ocean 

2.3 属性装饰器

 

属性装饰器属性描述符只能用来监视类中是否声明了某个名字的属性,在属性声明前进行声明。

属性装饰器表达式会在运行时当做函数进行调用,传入两个参数:

  • target: 被装饰的类
  • key: 被装饰类的属性名字

注意:属性描述符不作为参数传入属性装饰器。因为目前还没有办法在定义一个原型对象时描述一个实例属性,并且没有办法进行建议监听或修改一个属性的初始化方法。

  1. // 定义装饰器 
  2. function testDecorator(target: anykey: string): void { 
  3.   console.log("Target: ", target ); 
  4.   console.log("key: "key); 
  5.  
  6. function logError(errorMessage: string){ 
  7.   return function(target: anykey: string, desc: PropertyDescriptor){ 
  8.     const method = desc.value; 
  9.     desc.value = function(){ 
  10.       try { 
  11.         method(); 
  12.       }catch(err){ 
  13.         console.log(errorMessage); 
  14.          
  15.       } 
  16.     } 
  17.   } 
  18.  
  19. // 使用装饰器 
  20. class Boat{ 
  21.   @testDecorator 
  22.   color: string = "yellow"
  23.  
  24.   // @testDecorator 
  25.   get formattedColor(): string{ 
  26.     return  `this boat color is ${this.color}`; 
  27.      
  28.   } 
  29.  
  30.   @logError("Oops boat was sunk in ocean"
  31.   pilot(): void{ 
  32.     throw new Error() 
  33.     console.log("swish"); 
  34.      
  35.   } 

运行结果:

  1. Target:  {} 
  2. key:  color 

2.4 参数装饰器

 

参数装饰器用于类构造函数或方法声明。接收三个参数:

  • target: 被装饰的类
  • key:方法名
  • index:方法中的参数索引值
  1. // 定义装饰器 
  2. function testDecorator(target: anykey: string): void { 
  3.   console.log("Target: ", target ); 
  4.   console.log("key: "key); 
  5.  
  6. function logError(errorMessage: string){ 
  7.   return function(target: anykey: string, desc: PropertyDescriptor){ 
  8.     const method = desc.value; 
  9.     desc.value = function(){ 
  10.       try { 
  11.         method(); 
  12.       }catch(err){ 
  13.         console.log(errorMessage); 
  14.          
  15.       } 
  16.     } 
  17.   } 
  18.  
  19. // 参数装饰器 
  20. function parameterDecorator(target: anykey: string, index: number){ 
  21.   console.log(keyindex); 
  22.    
  23.  
  24. // 使用装饰器 
  25. class Boat{ 
  26.   @testDecorator 
  27.   color: string = "yellow"
  28.  
  29.   // @testDecorator 
  30.   get formattedColor(): string{ 
  31.     return  `this boat color is ${this.color}`; 
  32.      
  33.   } 
  34.  
  35.   @logError("Oops boat was sunk in ocean"
  36.   pilot(): void{ 
  37.     throw new Error() 
  38.     console.log("swish"); 
  39.      
  40.   } 
  41.  
  42.  
  43.   fast( 
  44.     @parameterDecorator speed: string, 
  45.     @parameterDecorator generateWake: boolean 
  46.   ): void{ 
  47.     if(speed === "fast"){ 
  48.       console.log("swish"); 
  49.     }else
  50.       console.log("nothing"); 
  51.        
  52.     } 
  53.   } 

运行结果:

  1. Target:  {} 
  2. key:  color 
  3. fast 1 
  4. fast 0 

小结

 

我们看到装饰器很方便为我们结果了许多问题。装饰器根据其装饰的对象不同,分为:类装饰器、属性装饰器、方法装饰器、参数装饰器。

原文链接:https://mp.weixin.qq.com/s/7qZjqNoo0G0lHryObCc85w