好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

TypeScript入门笔记(五)

接 上篇。

这篇主要记录TypeScript中的几种装饰器的概念与用法。装饰器(Decorators):用一种特性标注的写法作为声明,能够给类,方法,属性扩展功能,可以简单地理解为是非侵入式的行为修改。分为:类装饰器、方法装饰器、属性装饰器、访问器装饰器、参数装饰器。

  1   /*  *
   2    * 装饰器(Decorators):用一种特性标注的写法作为声明,能够给类,方法,属性扩展功能,可以简单地理解为是非侵入式的行为修改
   3    * 分为:类装饰器、方法装饰器、属性装饰器、访问器装饰器、参数装饰器
   4    * 注:在tsconfig.json中将打开 “"experimentalDecorators": true” 以启用装饰器功能
   5    */ 
  6  
  7   /*   ****************************类装饰器*******************************   */ 
  8   //  以下这个Person类使用了装饰器“yasuo” 
  9   //  @yasuo 
 10   class Person {
  11      roleLine: string |  undefined;
  12  
 13       constructor(readonly name: string, readonly birthDay: Date) {
  14           this .roleLine = "Hello everyone"
 15       }
  16  
 17      SayHi():  void   {
  18          console.log( this  .roleLine);
  19       }
  20   }
  21  
 22   /*  *
  23    * 装饰器其实也是一个方法,装饰器中可以做的事有三:
  24    * (1)做点自己想做的事
  25    * (2)扩展属性或者方法
  26    * (3)重载类的构造函数
  27    */ 
 28  
 29   //  参数target便代表Person类(的构造器) 
 30   function   yasuo(target: any) {
  31       //  (1)只要有类应用了这个装饰器,便会执行 
 32      console.log("Follow the wind, but watch your back." )
  33  
 34       //  (2)为Person类扩展一个Attach的方法 
 35      target.prototype.Attack =  function   () {
  36          console.log("Hasaki!" );
  37       }
  38  
 39       //  (3)重载构造函数 
 40       return   class extends target {
  41          roleLine: any = "Make it quick."
 42       }
  43   }
  44   //  这里指定为any类型是为了防止调用扩展方法Attack时TypeScript编译器报错 
 45  let hero: any =  new  Person("yasuo",  new  Date("2013-12-14" ));
  46  
 47  hero.SayHi();    //   控制台输出:Make it quick. 
 48   //  hero.Attack()   // 控制台输出:Hasaki! 
 49  
 50  
 51   /*   ****************************装饰器工厂******************************   */ 
 52   //   带参数的装饰器 
 53  @skin("黑夜使者" )
  54   class Hero {
  55      roleLine: string |  undefined;
  56  
 57       constructor(readonly name: string, readonly birthDay: Date) {
  58           this .roleLine = "welcome to LOL"
 59       }
  60  
 61      SayHi():  void   {
  62          console.log( this  .roleLine);
  63       }
  64   }
  65   //  定义“装饰器工厂” 
 66   function  skin(value: string) {       //   这是一个装饰器工厂 
 67       return   function  (target: any) {       //    这是装饰器 
 68           let line: string;
  69           switch   (value) {
  70               case  "黑夜使者" :
  71                  line = "我是变革之风"
 72                   break  ;
  73               case  "猩红之月" :
  74                  line = "Hasaki"
 75                   break  ;
  76               default  :
  77                  line = "Attack"
 78                   break  ;
  79           }
  80  
 81          target.prototype.Attack =  function   () {
  82               console.log(line);
  83           }
  84       }
  85   }
  86  
 87  let h1: any =  new  Hero("yasuo",  new  Date("2013-12-14" ));
  88  h1.Attack();     //  控制台输出:我是变革之风 

属性装饰器

  1   /*   ****************************属性装饰器******************************   */ 
  2   //   属性装饰器接收两个参数 
  3   //   参数一:对于静态成员是构造器,对于实例成员是类的原型对象 
  4   //   参数二:属性的名称 
  5  
  6   class Hero {
   7  
  8      @lineInjection("Hasaki")     //  使用装饰器为其赋值 
  9      roleLine: string |  undefined;
  10  
 11       constructor(readonly name: string, readonly birthDay: Date) {
  12       }
  13  
 14      SayHi():  void   {
  15          console.log( this  .roleLine);
  16       }
  17   }
  18  
 19   //  定义一个属性装饰器 
 20   function  lineInjection(line: string) {       //  装饰器的参数 
 21       return   function   (target: any, prop: any) {
  22          target[prop] =  line;
  23       }
  24   }
  25  
 26  let h1 =  new  Hero("yasuo",  new  Date("2013-12-14" ));
  27  h1.SayHi();      //  控制台输出:Hasaki 

方法装饰器

  1   /*   ****************************方法装饰器******************************   */ 
  2   //   用于监视,修改方法,接受3个参数 
  3   //   参数一:对于静态成员是构造器,对于实例成员是类的原型对象 
  4   //   参数二:方法的名称 
  5   //   参数三:方法的属性描述符,其中value属性就是当前方法的定义 
  6  
  7   class Person {
   8       constructor(public firstName: string, public lastName: string) { }
   9  
 10       @useFullName
  11      public SayHi():  void   {
  12          console.log(`i am ${ this  .firstName}`);
  13       }
  14   }
  15  
 16   //  定义一个方法装饰器,修改方法,让其输出全名 
 17   function   useFullName(
  18      target: object,          //  参数一:类的原型对象 
 19      propertyName: string,    //  参数二:成员的名称 
 20      descriptor: PropertyDescriptor   //  参数三:成员的描述信息 
 21  ):  void   {
  22  
 23       //  将改写前的原方法暂存下来 
 24      const sayLastName: Function =  descriptor.value;
  25  
 26       //  改写方法 
 27      descriptor.value =  function   () {
  28           //  先调用一次原方法 
 29          sayLastName.call( this  );
  30           //  再输出一次全名 
 31          console.log(`${ this .firstName} ${ this  .lastName}`)
  32       };
  33   }
  34  
 35  let mj =  new  Person("bond", "james" );
  36  
 37  mj.SayHi();      //  控制台输出:i am bond 
 38                   //  bond james 

方法参数装饰器

  1   /*   ****************************方法参数装饰器******************************   */ 
  2   //   可以用来监视方法传入的参数 
  3   //   和之前几个装饰器类似,接受的参数如下 
  4   //   参数一:对于静态成员是构造器,对于实例成员是类的原型对象 
  5   //   参数二:方法的名称 
  6   //   参数三:参数在方法中的位置(index) 
  7  
  8   class Greeter {
   9       greeting: string;
  10  
 11       constructor(message: string) {
  12           this .greeting =  message;
  13       }
  14  
 15       greet(@log name: string) {
  16           return  "Hello " + name + ", " +  this  .greeting;
  17       }
  18   }
  19  
 20   function   log(
  21       target: Object,
  22       propertyKey: string,
  23       parameterIndex: number) {
  24  
 25       console.log(target);
  26       console.log(propertyKey);
  27       console.log(parameterIndex);
  28  }

装饰器的执行顺序

如果一个对象中包含多个装饰器,如

 1   @f
  2   @g
  3  class x

那么他的执行顺序是f(g(x)),先执行下面的装饰器后再执行上面的。

若多种装饰器共存是,其执行顺序是:属性装饰器 → 方法装饰器 → 方法参数装饰器 → 类装饰器。

查看更多关于TypeScript入门笔记(五)的详细内容...

  阅读:59次