【Nest全栈之旅】第二章:我是如何理解装饰器的?

Nest系列概念篇,聊聊装饰器。

装饰器

基本概念

装饰器,顾名思义就是用来装饰某件物体,在一定程度上增加了某件物体的功能,以解决更多的实际需求。

举个栗子🌰,一间房子里面放了一张床,那么就实现了这个房间可以睡觉的基本需求,在这个基础上新增了沙发、红酒杯、电视机,那么就可以实现坐在沙发上摇着红酒看综艺节目的理想状态。此时沙发、红酒杯、电视机起到了装饰器的效果,在不影响房间可以用来睡觉的前提下扩展了更多的功能,实现松耦合和易扩展。

装饰器种类

上个例子中,沙发、红酒杯、电视机属于不同的装饰器,它们分别实现了不同的功能,同样的,常用的装饰器也分为以下几种:

  1. 类装饰器
  2. 方法装饰器
  3. 属性装饰器
  4. 参数装饰器

下面分别用几个简单的例子来说明。

ES6中装饰器使用

typescript 复制代码
/**
 * 类装饰器
 */
const doc: ClassDecorator = (target: any) => {
    target.prototype.name = 'jmin'
    console.log(target);
}
​
@doc
class App {
    constructor() {   
    }
}
​
const app: Record<string, any> = new App()
console.log('app name: ' + app.name);
​
​
/**
 * 属性装饰器
 */
const prop: PropertyDecorator = (target: Object, propertyKey: string | Symbol) => {
    console.log('------属性装饰器-------');
    
    console.log(target);
    console.log(propertyKey);
    
    console.log('------属性装饰器-------');

}
​
class User {
    @prop
    name: string = 'jmin'
}
​
​
/**
 * 方法装饰器
 */
const method: MethodDecorator = (target: Object, propertyKey: string | Symbol, descriptor: PropertyDescriptor) => {
    console.log("---------------方法装饰器-----------------");
    console.log(target);
    console.log(propertyKey);
    console.log(descriptor);
    console.log("---------------方法装饰器-----------------");
}
​
class User2 {
    @method
    getName() {
        return 'jmin';
    }
}
​
/**
 * 参数装饰器
 */
​
const param: ParameterDecorator = (target: Object, propertyKey: string | Symbol | undefined, index: number) => {
    console.log('-------------参数装饰器------------------');
    console.log(target);
    console.log(propertyKey);
    console.log(index);
    console.log('-------------参数装饰器------------------');   
}
​
class User3 {
    
    getName(@param name: string) {
        return name;
    }
}
​
const user3 = new User3();
console.log(user3.getName('jmin'));
​

Nest中的装饰器

nest中实现AOP思想的一种方式就是用装饰器,这些装饰器分为异常过滤器(exception filter)管道(pipes)守卫(guards)拦截器(interceptors)等等

扩展一个题外话,为什么nest中要实现AOP架构?

当一个请求过来的时候,一般会通过Controller控制器Services服务层Repository数据访问实体链路,当我们不使用AOP时,需要新增一些通用逻辑如(权限控制、日志统计、异常处理),就需要在每个请求逻辑中编写编写相关代码,这必然造成业务逻辑跟通用逻辑的耦合而让应用变得难以维护。

AOP切面思想是将所有请求外面包裹一层,所有的请求都会通过这个切面去处理通用逻辑,实现了业务逻辑松耦合和易扩展。

再回来看一下Nest中基础的装饰器:

typescript 复制代码
// person.controller.ts

@Controller('person')
export class PersonController {
  constructor(private readonly personService: PersonService) {}
​
  @Post('/create-person')
  create(@Body() createPersonDto: CreatePersonDto) {
    return this.personService.create(createPersonDto);
  }
}

上面可以看到,存在类装饰器、方法装饰器、参数装饰器 ,可以发现它们是支持接受参数或直接调用,如@Controller('person'),但是ES6中不支持直接调用装饰器啊,那是怎么实现呢?

答案是通过装饰器工厂,也叫柯里化

看下面的例子你就懂了:

typescript 复制代码
const doc2 = (param: string) : ClassDecorator => {
    console.log("param:", param);
    return (target: any) => {
        target.prototype.name = 'jmin'
        console.log(target);
    }
}
​
@doc2('person')
class App2 {
    constructor() {   
    }
}
​
const app2: Record<string, any> = new App2()
console.log('app2 name: ' + app2.name);

这就实现了跟Nest中相同的装饰器语法,实际上,Nest中恰恰也是通过这种方式来实现的。

Get(':id')请求装饰器为例:

这里接受的path参数就是:id这串玩意~

总结

通过类比方式介绍了装饰器本身,为了装饰某件物体才能够产生价值。

接着介绍装饰器的几种存在形态,以及ES6的基本实现,还介绍了Nest中装饰器的应用场景以及跟AOP思想的融合,最后翻了一下源码看Nest中装饰器的基本实现,一眼就看出跟ES6中实现的区别。

但,这不是全部,要实现Nest中的装饰器效果,还有一个很重要的概念就是元数据反射,它们有什么作用呢?存在的意义又是什么?

欲知后事如何,请看下节分享!!!

相关推荐
JarvanMo23 分钟前
Dart 3.13:小版本,大动作
前端
纯粹的热爱25 分钟前
Ubuntu 安装 Node.js 22.x(通过 NodeSource 官方源)
前端
Highcharts28 分钟前
如何选择正确的图表:驱动理解和洞察力的三部分框架(第3部分)
前端·数据可视化
智驭未来掌门人30 分钟前
利用FFmpeg快速实现一个RTSP推流服务器
后端
垚垚学技术_聚焦云原生42 分钟前
K8s Pod 完整生命周期详解
后端
JavaGuide1 小时前
Github 史诗级故障,与此同时,Cursor 版「GitHub」正式上线!
前端·后端
郭邯1 小时前
用 AI 写了一个经纬度格式转换工具,从需求到落地的完整过程
前端
不一样的少年_1 小时前
修了 Bug、做了重构,为什么老板还是觉得你没产出?
前端·后端·程序员
马可家的菠萝1 小时前
Vue3 + Canvas 手绘笔记工程化实践:别把画布只当成一张 PNG
前端·vue.js·算法
IMPYLH1 小时前
HTML 的 <h1>–<h6> 元素
前端·javascript·html