TypeScript学习笔记之装饰器Decorator

随着TypeScript和ES6里引入了类,在一些场景下我们需要额外的特性来支持标注或修改类及其成员。 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式。 Javascript里的装饰器目前处在 建议征集的第二阶段,但在TypeScript里已做为一项实验性特性予以支持。

注意 装饰器是一项实验性特性,在未来的版本中可能会发生改变。

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

命令行:

tsc --target ES5 --experimentalDecorators

装饰器

装饰器是一种特殊类型的声明,它能够被附加到类声明方法访问符属性参数上。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

类装饰器ClassDecorator

首先定义一个类

class Http{
  
}

定义一个类装饰器函数,target作为参数,它的值就是构造函数

const Base: ClassDecorator = (target) => {
  target.prototype.zl='zl';
  target.prototype.fn=()=>{
    console.log('zzz');
  }
}

使用的时候 直接通过@函数名使用

@Base
class Http {

}
let http = new Http() as any;
console.log(http.zl);
http.fn();

装饰器工厂

其实也就是一个高阶函数 外层的函数接受值 里层的函数最终接受类的构造函数,利用函数柯里化或者闭包

比如Base装饰器需要传递参数

const Base = (name: string) => {
  const f: ClassDecorator = (target) => {
    target.prototype.zl = name
    target.prototype.fn = () => {
      console.log('zzz');
    }
  }
  return f;
}
@Base('wo shi zl')
class Http {

}
let http = new Http() as any;
console.log(http.zl);
http.fn();

方法装饰器 MethodDecorator PropertyDescriptor

返回三个参数

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。
const Get = (url: string) => {
  const fn: MethodDecorator = (target, propertyKey, descriptor) => {
    // target:原型对象 | propertyKey:方法名称,比如getList | descriptor:描述
    console.log(target, propertyKey, descriptor);
  }
  return fn
}

@Base('wo shi zl')
class Http {
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  getList(data: any) {
    console.log(data);
  }
}
let http = new Http() as any;
http.fn();

输出结果

target:{} 
propertyKey:getList 
descriptor:{
  value: [Function: getList],
  writable: true,
  enumerable: false,
  configurable: true
}

可以看出value就是一个函数,值为getList

输出:

现在调用一下接口。descriptor.value(res.data)实际上就是相当于调用getList方法并传参数res.data=data

const Get = (url: string) => {
  const fn: MethodDecorator = (target, propertyKey, descriptor: PropertyDescriptor) => {
    // target:原型对象 | propertyKey:方法名称,比如getList | descriptor:描述
    console.log(target, propertyKey, descriptor);
    axios.get(url).then((res) => {
      descriptor.value(res.data)
    })
  }
  return fn
}

@Base('wo shi zl')
class Http {
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  getList(data: any) {
    console.log(data.result.list);
  }
}
let http = new Http() as any;
http.fn();

参数装饰器 ParameterDecorator

返回三个参数

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 参数在函数参数列表中的索引。
const Result=()=>{
  const fn:ParameterDecorator=(target, propertyKey, parameterIndex)=>{
    console.log(target, propertyKey, parameterIndex);
  }
  return fn;
}

@Base('wo shi zl')
class Http {
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  getList(@Result() data: any) {
    // console.log(data.result.list);
  }
}

输出:

比如我们想要在getList方法中直接输出data的值,就相当于data是已经解析出来的data.result

需要使用一个库reflect-metadata

npm i reflect-metadata -D

可以快速存储元数据然后在用到的地方取出来 defineMetadata getMetadata

const Get = (url: string) => {
  const fn: MethodDecorator = (target, propertyKey, descriptor: PropertyDescriptor) => {
    // target:原型对象 | propertyKey:方法名称,比如getList | descriptor:描述
    // console.log(target, propertyKey, descriptor);
    axios.get(url).then((res) => {
      const key = Reflect.getMetadata('key', target)
      descriptor.value(key ? res.data[key] : res.data)
    })
  }
  return fn
}
const Result = () => {
  const fn: ParameterDecorator = (target, propertyKey, parameterIndex) => {
    // console.log(target, propertyKey, parameterIndex);
    Reflect.defineMetadata('key', 'result', target);

  }
  return fn;
}
@Base('wo shi zl')
class Http {
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  getList(@Result() data: any) {
    // console.log(data.result.list);
    console.log(data);
  }
}

属性装饰器

返回两个参数

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 属性的名字。
const Name: PropertyDecorator = (target, propertyKey) => {
  console.log(target, propertyKey);
}
@Base('wo shi zl')
class Http {
  @Name
  name: string
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  getList(@Result() data: any) {
    // console.log(data.result.list);
    // console.log(data);
  }
}
let http = new Http() as any;
http.fn();

输出:

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值