ts 装饰器

前言

ts中有几种装饰器类型:

  • 类装饰器 ClassDecorator
  • 方法装饰器 MethodDecorator
  • 参数装饰器 ParameterDecorator
  • 属性装饰器 PropertyDecorator

一、类装饰器 ClassDecorator

  • 功能 & 使用场景:不想破坏原有的类的结构,又不想去读内部的代码逻辑,只想 给类增加一些新的属性或方法,可对该类使用装饰器
  • 装饰器需要定义为 ClassDecorator 类型
  • 装饰器回传参数 target, 是调用者的 构造函数
  • 两种使用方式:
    • 在 class 前 @DecoratorName
    • 在 class 后 DecoratorName(className)

1、类装饰器的简单使用

const DecoratorClassDemo: ClassDecorator = (target) => {
  // 回传的 target 是调用者的构造函数
  // 可以额外定义属性、方法
  target.prototype.color = 'blue'
  target.prototype.showColor = () => {
    console.log('哈哈哈哈')
  }
}

// 写法一:若担心浏览器不支持,可以使用写法二
@DecoratorClassDemo
class Http {
  // 不想读里面的逻辑,又想加一些东西,并且不破坏原有的结构,可以考虑在外层使用装饰器
}
// 写法二:
// DecoratorClassDemo(Http)

// 将类实例化后,可以访问到装饰器里新增的属性和方法
const http = new Http() as any
console.log('http.color', http.color) // blue
http.showColor()

如果想要 传参数 给类装饰器,怎么做?

2、装饰器工厂

可以先把它定义为 普通函数(保证参数的接收),然后在其 内部返回一个装饰器函数 即可(闭包)

// 可以先把它定义为普通函数(保证参数的接收),然后在其内部返回一个装饰器函数即可
const DecoratorClassDemo2 = (msg: string, age: number) => {
  const fn: ClassDecorator = (target) => {
    target.prototype.msg = msg
    target.prototype.age = age
  }
  return fn
}
@DecoratorClassDemo2('hahaha', 18)
class Http2 {
  // .....
}
const http2 = new Http2() as any
console.log('类装饰器传参---', http2.msg)
console.log('类装饰器传参---', http2.age)

同样的方式在其他装饰器中也有使用

二、方法装饰器 MethodDecorator

  • 顾名思义,就是对 方法 使用装饰器,在方法前 @DecoratorName
  • 方法装饰器需要声明为 MethodDecorator 类型
  • 方法装饰器回传参数:target, propertyKey, descriptor
    • target:调用者的 原型
    • propertyKey: 调用者的 key,即 方法名称
    • descriptor:调用者的 描述
  • 方法装饰器 想要 回调数据给调用者,需要 把 descriptor 声明为 PropertyDescriptor 类型,通过 descriptor.value 返回

例:写一个简单的Get请求装饰器

// 安装:npm i axios 
import axios from 'axios'

const Get = (url: string) => {
  // 这里注意把 descriptor 定义为 PropertyDescriptor 类型
  const fn: MethodDecorator = (target, propertyKey, descriptor: PropertyDescriptor) => {
    // 【target】:{constructor: ƒ, getList: ƒ}
    // 【propertyKey】:getList
    // 【descriptor】:{writable: true, enumerable: false, configurable: true, value: ƒ}

    axios.get(url).then(res => {
      // 拿到结果后通过 descriptor 的 value 返回(注意value是个函数)
      descriptor.value(res.data) 
    })
  }
  return fn
}

class Http3 {
  // 对 getList  使用 方法装饰器 Get
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=1&size=10')
  getList (data: any) {
    console.log(data)
  }
}

最终打印出的 data:

在这里插入图片描述

三、参数装饰器 ParameterDecorator

  • 顾名思义,对 参数 使用装饰器,在参数前 @DecoratorName
  • 参数装饰器需要定义为 ParameterDecorator 类型
  • 参数装饰器回传参数: target, propertyKey, parameterIndex
    • target:调用者的 原型
    • propertyKey:调用者的 方法名称
    • parameterIndex:该参数是方法中的 第几个参数
  • 需要用到插件 reflect-metadata使用元数据
    • 安装命令: npm i reflect-metadata
    • tsconfig.json 中需要将 emitDecoratorMetadata 开启
    • Reflect.defineMetadata存入元数据,参数如下:
      • metadataKey: 所要存元数据的 key
      • metadataValue: 对应的 value
      • target: 存入的 目标
    • Reflect.getMetadata取出元数据,参数如下:
      • metadataKey:所要取的元数据的 key
      • target:所要取的 目标

在上面的基础上继续造例子,将 参数data 处理为优先返回内部的 result

import axios from 'axios'
import 'reflect-metadata'

const Result = () => {
  const fn: ParameterDecorator = (target, propertyKey, parameterIndex) => {
    // 【target】:{constructor: ƒ, getList: ƒ} 
    // 【propertyKey】:getList 
    // 【parameterIndex】:0
    
    // 存入数据:key='result'
    Reflect.defineMetadata('key', 'result', target)
  }
  return fn
}


const Get2 = (url: string) => {
  const fn: MethodDecorator = (target, propertyKey, descriptor: PropertyDescriptor) => {
    axios.get(url).then(res => {
      // 在这里取出所存元数据的 key 所存的 value(字符串 result) ,看返回的数据中有没有这个值,有的话直接返回
      const k = Reflect.getMetadata('key', target)
      
      descriptor.value(k ? res.data[k] : res.data)
    })
  }
  return fn
}
class Http4 {
  @Get2('https://api.apiopen.top/api/getHaoKanVideo?page=1&size=10')

  // 比如:对这里的 参数data 使用装饰器 Result,目的是自动取出 data 中的 result 属性
  // @Result 优先于 @Get2 先执行,在 @Result 存元数据,在 @Get2 中取元数据
  getList(@Result() data: any) {
    console.log(data)
  }
}

经过参数装饰器后,打印出的 data:

在这里插入图片描述

四、属性装饰器 PropertyDecorator

  • 属性 的装饰器,在属性前 @DecoratorName
  • 属性装饰器需要定义为 PropertyDecorator 类型
  • 属性装饰器回传参数:target, propertyKey
    • target:调用者的 原型
    • propertyKey: 调用者的 属性名字
const Color: PropertyDecorator = (target, propertyKey) => {
  // 【target】:{constructor: ƒ} 
  // 【propertyKey】:color
  
  // 一些操作...
}
class Http5 {
  // 对 属性color 使用 属性装饰器Color
  @Color
  color:string
  constructor () {
    this.color = 'blue'
  }
}

看的时候很懵逼,一定要多敲才能理解深刻!!

如果只看文章太痛苦,可以看文章最上面引言中提到的B站视频教程,然后再敲一遍

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值