【TypeScript】装饰器 Decorator

概述

在ES6中,就已经出现的装饰器。装饰器(Decorator)是一种与类(class)相关的语法,用来注释或修改类和类方法。装饰器其实就是一个编译时执行的函数。

装饰器(Decorators)是 TypeScript 中一种特殊的语法,用于在类、方法、属性等元素上附加元数据或修改其行为。装饰器提供了一种在不改变类的定义的情况下,对类进行扩展或修改的方式。

装饰器的使用类似于注解,在代码中以 @ 符号开头,后面紧跟装饰器工厂函数或表达式。装饰器工厂函数会在装饰器被应用到类、方法等上时被调用,它接受不同的参数,具体取决于被装饰的目标。

其实装饰器就是一个可以提前拿到类本身(或原型对象)并预处理的函数。当类定义的时候被调用。

使用装饰器之前,需要先在 tsconfig.json 中开启两个配置:

在这里插入图片描述

以下是一些常见的装饰器的用法和示例:

1. 参数装饰器

import axios from 'axios'
// 使用 defineMetadata 需要 npm i reflect-metadata
import 'reflect-metadata'
const Get = (url: string) => {
  // _ 是一个占位符,防止和下面的 key 重名
  const fn: MethodDecorator = (target, _, descriptor: PropertyDescriptor) => {
    // console.log(target, key, descriptor)
    const key = Reflect.getMetadata('key',target)
    axios.get(url).then(res => {
      descriptor.value(key ? res.data[key] : res.data)
    })
  }
  return fn
}
const Result = () => {
  const fn: ParameterDecorator = (target, key, index) => {
    Reflect.defineMetadata('key', 'result', target)
    // console.log(target, key, index)
     // {} getList 0  --> 原型对象 方法名字 参数所在的位置
  }
  return fn
}
class Http {
  @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10')
  // @Result() 参数装饰器
  getList(@Result() data: any) {
    console.log(data);
  }
}

2. 类装饰器:

类装饰器用于装饰类的声明。它接受一个参数,即被装饰的类的构造函数。

它的应用场景就是当不直接破坏某个类的构造函数,而在外面为类的构造函数添加方法和属性。

function logClassName(constructor: Function) {
  console.log(`Class name: ${constructor.name}`);
}

@logClassName
class MyClass {
  // ...
}

// 写成匿名函数形式:
const Base:ClassDecorator = (target) =>{
    console.log(target)
    target.prototype.xx = 'xx'
    target.prototype.fn = () =>{
      console.log('fn')
    }
}
@Base
class Http {
// ...
}
const http = new Http() as any
// Base(Http) // 删掉 @Base,写成这样也是可以的
http.fn()

传参(可以使用闭包 | 函数柯里化):

function logClassName(constructor: Function) {
  console.log(`Class name: ${constructor.name}`);
}

@logClassName
class MyClass {
  // ...
}

// 写成匿名函数形式:
const Base = (name) => {
  const fn: ClassDecorator = (target) => {
    console.log(target)
    target.prototype.xx = name
    target.prototype.fn = () => {
      console.log('fn')
    }
  }
  return fn
}
@Base('我是新的xx')
class Http {
  // ...
}
const http = new Http() as any
// Base(Http) // 删掉 @Base,写成这样也是可以的
http.fn()

3. 方法装饰器:

方法装饰器用于装饰类的方法。它接受三个参数:目标类的原型,方法名称(如下面的 getList),方法的属性描述符(可枚举,可修改什么的)。

function logMethod(target: any, methodName: string, descriptor: PropertyDescriptor) {
  console.log(`Method ${methodName} is decorated.`);
}

class MyComponent {
  @logMethod
  doSomething() {
    // ...
  }
}

// 实例:
import axios from 'axios'
const Get = (url: string) => {
    const fn: MethodDecorator = (target, key, descriptor: PropertyDescriptor) => {
      console.log(target, key, descriptor)
      axios.get(url).then(res => {
      //  descriptor.value 就是函数 getLsit 这里相当于函数调用
        descriptor.value(res.data)
      })
    }
    return fn
}
class Http {
    @Get('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10') 
    getList(data: any) {
      console.log(data.result.list)
    }
}

axios 同时封装了 浏览器环境和node环境的 请求方法。node环境不能使用 XHR,只能使用原生的 http 和 fetch。

4. 属性装饰器:

属性装饰器用于装饰类的属性。它接受两个参数:目标类的原型和属性名称。

function readonly(target: any, propertyName: string) {
  Object.defineProperty(target, propertyName, { writable: false });
}

class Person {
  @readonly
  name: string = "Alice";
}

5. 装饰器工厂:

装饰器工厂是一个函数,用于生成装饰器。它可以接受参数,用于传递额外的配置信息。

function log(message: string) {
  return function(target: any, propertyName: string) {
    console.log(`Logged message: ${message}`);
  };
}

class Product {
  @log("Product created")
  name: string;
}

需要注意的是,装饰器的执行顺序是从上往下的,即从最外层的装饰器开始执行。装饰器可以叠加在一起,对同一个目标进行多次装饰。

应用场景

可以看到,使用装饰器存在两个显著的优点:

  • 代码可读性变强了,装饰器命名相当于一个注释
  • 在不改变原有代码情况下,对原来功能进行扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秀秀_heo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值