ES6 装饰器 和 Nest 装饰器

433 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情

ES6 装饰器

ES6 提案里谈到装饰器(Decorator),其是一个函数,用于修改类和类方法的函数。写成@ + 函数名

类的装饰

function isDecorator(target) {
  target.isTest = true;
}
​
@isDecorator
class myExample {}
​
console.log(myExample.isDecorator) // true

以上代码,@isDecorator 是一个装饰器,修改了 myExample 类的行为,并增加了一个 isTest 静态属性。装饰器 isDecorator 的参数 taget 就是被装饰的类 myExample 本身。

方法的装饰

class MyExample {
  @readonly
  getInfo() { return `${this.name}, ${this.age}` }
}
​
function readonly(target, name, descriptor){
  // ......
}

上面代码中,装饰器readonly用来装饰“类”的getInfo方法。装饰器函数 readonly 有三个参数,第一个参数是所装饰的目标对象,第二个参数是所要装饰的属性名,第三个参数是该属性的描述对象。

Nest 装饰器

ES2016 装饰器是一个表达式,它返回一个可以将目标、名称和属性描述符作为参数的函数。可以为类、方法或属性定义装饰器。

内置装饰器

Nest 是基于 装饰器这种特性进行创建的。所以其提供了很多内置的装饰器

  • 核心类:@Controller、 @ Injectable 、@UseInterceptors、@UsePipes等等
  • Http 类:@Request(),@Req()、@Request(),@Req()
  • 模块类:@Global、@Module

Nest 支持自定义装饰器

首先,createParamDecorator 方法创建一个装饰器

export const UserDecorator = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
  const request = ctx.switchToHttp().getRequest();
  return request.user;
});

使用 createParamDecorator 创建装饰器时,可以通过 data 参数将参数传递给装饰器。

创建后就可以直接使用,且其允许在任何地方使用

@Get()
async findOne(@UserDecorator() user: UserEntity) {
  console.log(user);
}

使用管道

将管道应用到自定义装饰器上

@Get()
async findOne(@User(new ValidationPipe()) user: UserEntity) {
  console.log(user);
}

装饰器聚合

Nest 提供了一种聚合多个装饰器的方法 applyDecorators,就可以将一系列的行为装饰到你的类、方法或属性上面

export function Auth(...roles: Role[]) {
  return applyDecorators(
    SetMetadata('roles', roles),
    UseGuards(AuthGuard, RolesGuard),
    ApiBearerAuth(),
    ApiUnauthorizedResponse({ description: 'Unauthorized"' })
  );
}

主要是用的是 applyDecorators方法自定义出一个聚合的装饰器。当让一个类也是支持有多个装饰器,执行顺序将按顺序执行

@Get('users')
@Auth('admin')
@UserDecorator()
findAllUsers() {}

通过使用装饰器可以增加某类的特性,也可以将公共抽离出来当作装饰器。

可使用场景:

  • 传入参数类型。
  • 对返回值的排序、过滤。
  • 对某功能进行节流、防抖或其他的功能性代码。
  • 一些函数逻辑本身无关的、重复性的代码抽离出来。