目录
一、装饰器的作用
是一种在不改变原类和使用继承的情况下,动态地扩展对象功能
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上
二、结构
@Base
class Http {
}
本质上就是一个普通的函数,
@expression
的形式其实是Object.defineProperty
的语法糖expression
求值后必须也是一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入
配置
- tsc --init 初始化 tsconfig.json
- 打开以下两行注释,开启装饰器
三、装饰器的类型
1. 类装饰器
// 类装饰器:可以不修改类本身的情况下,给类添加属性和方法等,参数 target 是类的构造函数
const Base: ClassDecorator = (target) => {
console.log(target);
target.prototype.xiaoman = 'xiaoman';
target.prototype.fn = () => {
console.log('111111111');
}
}
@Base
class Http {
}
const http = new Http() as any;
http.fn();
2. 装饰器工厂
装饰器工厂:利用闭包进行传参,因为原本默认的参数是 target 所以要再封装一层
// 装饰器工厂:利用闭包进行传参,因为原本默认的参数是 target 所以要再封装一层
import axios from 'axios'
namespace d2 {
const Base = (name: string) => {
const fn: ClassDecorator = (target) => {
// console.log(target);
target.prototype.name = name;
}
return fn;
}
@Base('mike')
class Http {
}
const http = new Http() as any;
console.log(http.name);
}
3. 方法装饰器
参数
- target:对象的原型
- propertyKey:方法的名称
- descriptor:方法的属性描述符
const Get = (url: string) => {
const fn: MethodDecorator = (target, key, descriptor) => {
console.log(target, key, descriptor);
}
return fn;
}
class Http {
@Get('../data.json')
getList(data: any) {
console.log(data);
}
}
打印结果
应用
用于封装 axios 发送请求,只需要传入参数即可在 getList 中获得结果
const Get = (url: string) => {
const fn: MethodDecorator = (target, key, descriptor: PropertyDescriptor) => {
axios.get(url).then((res: any)=> {
descriptor.value(res.data); // descriptor.value 的值就是修饰的方法 getList
})
}
return fn;
}
class Http {
@Get('http://localhost:3000/data.json')
getList(data: any) {
console.log(data);
}
}
输出结果
4. 参数装饰器
参数
- target :当前对象的原型
- key :参数所在的函数名称
- index:参数数组中的位置
const Param: ParameterDecorator = (target, key, index) => {
console.log(target, key, index);
}
class Http {
getList(@Param data: any) {
console.log(data);
}
}
打印结果
应用场景:相对较少,可以用于打印参数的信息,也可以用于获取参数前的一些操作,简单来说就类似于函数之前的中间件
5. 属性装饰器(不常用)
参数
- target:对象的原型
- propertyKey:属性的名称
const AgeDec: PropertyDecorator = (target, propertyKey) => {
console.log(target, propertyKey);
}
class Http {
@AgeDec
age: number;
constructor() {
this.age = 20;
}
}
打印结果
四、总结
可以看到,使用装饰器存在两个显著的优点:
- 代码可读性变强了,装饰器命名相当于一个注释
- 在不改变原有代码情况下,对原来功能进行扩展