其实装饰器是一种注解,在各种框架使用了装饰器。例如:前端框架Angular和服务端框架Nestjs,由于自己需要学服务端框架Nestjs,装饰器在Nestjs中比较常见的。它还可以附加到方法、属性、类或者参数。这种装饰器的编译过程与我们平时的生活上有关系,例如说我的电脑里很多硬件,这种时候表示方法,硬件包括有内存条,显卡,硬盘等。有一些硬件损坏,需要去换新局部的硬件,而不是换整个电脑。
装饰器的语法比较简单,如果要使用装饰器,需要加上符号@即可,最后装饰器就会被调用到目标上。
1.开启装饰器
如果需要开启装饰器,首先找到tsconfig.json文件里找到experimentalDecorators开启即可。
2.装饰器工厂
需要一个装饰器如何应用到目标上,然后写一个装饰器工厂函数,这个相当于简单的装饰器,最后返回一个表达式。
const Base = (name:string) =>{
// 使用相当于闭包
const fn:ClassDecorator = (target) =>{
target.prototype.__xiaobin = name
target.prototype.fn = () =>{
// console.log('我爱篮球')
}
}
return fn
}
例上的代码,就是普通的装饰器,反正不管怎样最后是返回一个表达式。
3.类装饰器
类装饰器本身就是一种构造函数,应用于类构造函数,可以修改类定义。类装饰器英文称为ClassDecorator,target的参数是返回为类构造函数。
@deatil
class Info{
greeting:string;
constructor(message:stirng){
this.greeting = message
}
greet() {
return "world"+this.greeting
}
}
console.log(new Info('james'));
用类装饰器@deatil,然后应用在Info类。
4.属性装饰器
属性装饰器在函数的传参一般是有两个:traget对于静态成员来说是类构造器,对于实例成员来说是类的原型链;另外是属性的名称。属性装饰器英文称为PropertyDecorator。
class Info{
@format("hello,%c")
greeting:string;
constructor(message:string){
this.greeting = message
}
greet(){
let str = getFormat(this,"greeting")
return str.replace("%c",this.greeting)
}
}
@format()就是装饰器工厂,当被调用时,一般会读取格式的元数据。
5.参数装饰器
参数装饰器在构造函数参数有三种:traget对于静态成员来说是类构造器,对于实例成员来说是类的原型链; propertyKey为属性的名称(注意必须是方法的名称);index就是参数在方法中位置的下标。参数装饰器英文称为ParameterDecorator。
const Result = () =>{
const fn:ParameterDecorator = (target,key, index) =>{
Reflect.defineMetadata('key','result',target)
}
return fn
}
前提是要安装reflect-metadata,这样方便获取到元数据。
6.方法装饰器
方法装饰器在函数中参数有:traget对于静态成员来说是类构造器,对于实例成员来说是类的原型链;propertyKey为属性的名称;descriptor为属性的描述器。方法装饰器英文称为MethodDecorator 和PropertyDescriptor。
const Get = (url:string) =>{
const fn:MethodDecorator = (target,_:any,descriptor:PropertyDescriptor) =>{
const key = Reflect.getMetadata('key',target)
axios.get(url).then(res=>{
descriptor.value(key? res.data[key]:res.data)
})
}
return fn
}
其实方法装饰器和属性装饰器不同在于descriptor参数。通过这个参数可以修改方法的实现。
7.访问器装饰器
其实和方法装饰器一样的,但是区别在于参数为key不同,key有四种get、set、enumerable、configurable。
class Info{
private point = {x:0,y:0}
set pint(value:{x:number,y:number}){
this.point = value;
}
get pint(){
return this.point
}
}
例上的把这个变量名改为不可修改值。