什么是装饰器 装饰器-Decorators 在 TypeScript 中是一种可以在不修改类代码的基础上通过添加标注的方式来对类型进行扩展的一种方式
 
在 TypeScript 中,装饰器只能在类中使用
 
装饰器语法 装饰器的使用极其的简单
装饰器本质就是一个函数 
通过特定语法在特定的位置调用装饰器函数即可对数据(类、方法、甚至参数等)进行扩展 
 
启用装饰器特性 
experimentalDecorators: true 
 
tsconfig.json中进行配置
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function  log (target:Function ,name:string ,descriptor:PropertyDescriptor ) {        let  fn = descriptor.value   descriptor.value = function (a:number ,b:number  ) {     let  result = fn(a,b)       console .log('日志:' ,{       name,       a,       b,       result     })      return  result   } } class  M {  @log    static  add(a:number ,b:number ){     return  a+b   } } 
 
装饰器细节 装饰器 是一个函数,它可以通过 @装饰器函数 这种特殊的语法附加在 类、方法 、访问符、属性、参数 上,对它们进行包装,然后返回一个包装后的目标对象(类、方法 、访问符、属性、参数 ),装饰器工作在类的构建阶段,而不是使用阶段 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 function  d1 (target:Function  ) {  console .log(typeof  target,target) } function  d11 (target:Function  ) {  console .log(typeof  target,target) } function  d2 (target:any ,name:string  ) {  console .log(typeof  target,name) } function  d3 (target:any ,name:string ,descriptor: PropertyDescriptor ) {  console .log(typeof  target,name,descriptor) } function  d4 (target:any ,name:string ,descriptor: PropertyDescriptor ) {  console .log(typeof  target,name,descriptor) } function  d5 (target:any ,name:string ,index: number  ) {     console .log(typeof  target,name,index) } @d1  @d11   class  MyClass {     @d2    a: number ;      @d2    static  property1: number ;      @d3    get  b() {      return  1 ;    }      @d3    static  get  c() {     return  2 ;   }      @d4    public  method1(@d5  x: number ,@d5  y:number ) {        }      @d4    public  static  method2() {} } 
 
类装饰器 目标
参数
属性装饰器 目标
参数
第一个参数
静态方法:类的构造函数 (装饰static property1那么为MyClass) 
实例方法:类的原型对象 (装饰的a: number;那么为new MyClass()实例后的对象) 
 
 
第二个参数
 
 
访问器装饰器 目标
参数
第一个参数 (同属性装饰器)
 
第二个参数
 
第三个参数
 
 
方法装饰器 目标
参数
参数装饰器 目标
参数
装饰器执行顺序 实例装饰器
        属性 => 访问符 => 参数 => 方法
静态装饰器
        属性 => 访问符 => 参数 => 方法
类
        类
装饰器工厂 如果我们需要给装饰器执行过程中传入一些参数的时候,就可以使用装饰器工厂来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 function  log (callback: Function  ) {  return  function (target:Function ,name:string ,descriptor:PropertyDescriptor ) {     let  value = descriptor.value     descriptor.value = function (x: number , y: number  ) {       let  result = value(x,y)       callback({         type ,         a,         b,         result       });       return  result;     }   } } class  M{  @log (function (result:any  ) {     console .log('1111' ,result)   })   static  add(x: number , y: number ){     return  x + y   }   @log (function (result:any  ) {     console .log('222' ,result)   })   static  sub(x: number , y: number ){     return  x - y   } } let  v1 = M.add(1 , 2 );console .log(v1);let  v2 = M.sub(1 , 2 );console .log(v2);
 
元数据 在 装饰器 函数中 ,我们可以拿到 类、方法 、访问符、属性、参数 的基本信息,如它们的名称,描述符 等,但是我们想获取更多信息就需要通过另外的方式来进行:元数据
什么是元数据? 元数据 :用来描述数据的数据,在我们的程序中,对象、类 等都是数据,它们描述了某种数据,另外还有一种数据,它可以用来描述 对象、类,这些用来描述数据的数据就是 元数据
比如一首歌曲本身就是一组数据,同时还有一组用来描述歌曲的歌手、格式、时长的数据,那么这组数据就是歌曲数据的元数据
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 function  L (type ?:string  ) {  return  function (target:Function  ) {     target.prototype.type = type    } } function  log (type ?: string  ) {  return  function (target:Function ,name:string ,descriptor:PropertyDescriptor ) {          let  value = descriptor.value     descriptor.value = function (x: number , y: number  ) {       let  result = value(x,y)       let  _type = type        if (!_type){         _type = typeof  target ===='function' ?target.prototype.type : target.type       }       console .log({         _type,         a,         b,         result       });       return  result;     }   } } @L ('log' )class  M{  @log ('local' )   static  add(x: number , y: number ){     return  x + y   }   @log ()   static  sub(x: number , y: number ){     return  x - y   } } let  v1 = M.add(1 , 2 );console .log(v1);let  v2 = M.sub(1 , 2 );console .log(v2);
 
会添加额外的属性
 
定义元数据 使用 reflect-metadata 
首先,需要安装 reflect-metadata
1 npm install reflect-metadata 
 
我们可以 类、方法 等数据定义元数据
元数据会被附加到指定的 类、方法 等数据之上,但是又不会影响 类、方法 本身的代码 
 
设置
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
metadataKey:meta 数据的 key 
metadataValue:meta 数据的 值 
target:meta 数据附加的目标 
propertyKey:对应的 property key 
 
调用方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import  "reflect-metadata" @Reflect .metadata("n" , 1 )class  A {    @Reflect .metadata("n" , 2 )     public  static  method1() {     }      	@Reflect .metadata("n" , 4 )   	public  method2() {     } } Reflect.defineMetadata('n' , 1 , A); Reflect.defineMetadata('n' , 2 , A, 'method1' ); let  obj = new  A();Reflect.defineMetadata('n' , 3 , obj); Reflect.defineMetadata('n' , 4 , obj, 'method2' ); console .log(Reflect.getMetadata('n' , A));console .log(Reflect.getMetadata('n' , A, ));
 
获取
Reflect.getMetadata(metadataKey, target, propertyKey)
参数的含义与 defineMetadata 对应
使用元数据的 log 装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 import  "reflect-metadata" function  log (type ?: string  ) {  return  function (target:Function ,name:string ,descriptor:PropertyDescriptor ) {          let  value = descriptor.value     descriptor.value = function (x: number , y: number  ) {       let  result = value(x,y)       let  _type = type        if (!_type){         if (typeof  target ===='function' ){           _type = Reflect.getMetadata("type" , target);         }else {           _type = Reflect.getMetadata('type' ,target.constructor )         }       }       console.log({          _type,         a,         b,         result       } );      return  result;     }   } } @Reflect .metadata('type' ,'storage' )class  M{  @log ('local' )   static  add(x: number , y: number ){     return  x + y   }   @log ()   static  sub(x: number , y: number ){     return  x - y   } } let  v1 = M.add(1 , 2 );console .log(v1);let  v2 = M.sub(1 , 2 );console .log(v2);