【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中的装饰器效果,还有一个很重要的概念就是元数据反射,它们有什么作用呢?存在的意义又是什么?

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

相关推荐
有梦想的刺儿7 分钟前
webWorker基本用法
前端·javascript·vue.js
cy玩具28 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json