用于给类、方法、属性等添加元数据或修改其行为,清晰地表达了意图,增加代码的可读性。
注意:装饰器是一种实验性的功能,需要启用实验性选项,并且它在未来版本可能会发生变化。
需要在 tsconfig.json 中打开装饰器语法:
"compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true }
类装饰器(ClassDecorator)
可以不去破坏原有类自身的结构,而给类添加新的属性或方法。(起一个修饰的作用)
const Base: ClassDecorator = (target) => {
// target为Http的构造函数
target.prototype.name = "张三";
target.prototype.func = () => {
console.log("我是新增加的方法");
};
};
@Base // 装饰器用@修饰(加大写字母),它会自己去调用装饰器函数,不需要我们手动再去调用
class Http {
// ...
}
const http = new Http() as any;
http.func();
http.name;
装饰器函数内会传递一个被装饰的类的构造函数(target),有了这个构造函数就可以不去破坏原有类自身的结构,而给类添加新的属性或方法。
- target:构造函数
有的浏览器可能不支持@Base,可以使用它的底层原理来表示:
class Http {
// ...
}
const http = new Http() as any;
Base(Http);
http.func();
http.name;
方法装饰器(MethodDecorator、PropertyDescriptor)
可以对某个方法进行封装,简化使用方法。
import axios from "axios";
const Get = (url: string) => {
const fun: MethodDecorator = (
target,
key,
descriptor: PropertyDescriptor
) => {
axios.get(url).then((res) => {
descriptor.value(res.data);
});
};
return fun;
};
class Http {
@Get("https://sdfdsf") // 定义方法装饰器,这样直接输入url地址就可以获得值
getList(data: any) {
// @Get里返回的值会自动传递到参数里
console.log(data);
}
}
- target:原型对象
- key:装饰的方法名
- descriptor:描述符
参数装饰器(ParameterDecorator)
简化获取的参数。比如要获取的数据为 data.result.list,有了参数装饰器直接使用 data 就能获取到。
import "relect-metadata";
const Get = (url: string) => {
const fun: MethodDecorator = (
target,
_key: any,
descriptor: PropertyDescriptor
) => {
const key = Reflect.getMetadata("key", target);
axios.get(url).then((res) => {
descriptor.value(key ? res.data[key] : res.data);
});
};
return fun;
};
const Result = () => {
const fun: ParameterDecorator = (target, key, index) => {
Reflect.defineMetadata("key", "result", target);
};
return fun;
};
class Http {
@Get("https://sdfdsf")
getList(@Result() data: any) {
// 定义参数装饰器
console.log(data);
}
}
- @Result()比@Get()优先执行。
relect-metadata是一个存储、操作元数据的库。
- target:原型对象
- key:装饰的方法名
- index:参数所在的位置
属性装饰器(PropertyDecorator)
const Name: PropertyDecorator = (target, key) => {
console.log(target, key);
};
class Http {
@Name
xiaohan: string;
}
- target:原型对象
- key:属性名
装饰器工厂
利用函数柯里化,向装饰器传递参数,并且与装饰器函数内传递的参数区分。
const Base = (name: string) => {
const fn: ClassDecorator = (target) => {
target.prototype.name = name;
target.prototype.func = () => {
console.log("我是新增加的方法");
};
};
return fn;
};
@Base("李四")
class Http {
// ...
}
const http = new Http() as any;
console.log(http.name); // 李四