(TS)装饰器

发布时间 2023-07-01 12:58:33作者: oOLzYOo

准备工作:开启ts的装饰器特性,需要在tsconfig.json中开启experimentalDecorators。

{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true
  }
}

类装饰器

类装饰器在类声明之前声明。类装饰器应用于类的构造函数,可用于观察、修改或替换类定义。类装饰器不能用于声明文件或任何其他环境上下文(例如声明类)。

类装饰器的表达式将在运行时称为函数,装饰类的构造函数作为其唯一的参数。

如果类装饰器返回一个值,它将用提供的构造函数替换类声明。

下面是两个使用例子,一个无参,一个有参:

const getEat: ClassDecorator = (constructor: Function) => {
    constructor.prototype.message = (context:string) => {
        console.log(context);
      }
}
function getRun(txt: string):(constructor: Function)=>void{
    return (constructor:Function)=>{
        constructor.prototype.run=()=>{
            console.log(txt)
        }
    }
}
@getEat
class apple {
    public logMsg(){
        (this as any).message('成功啦')
    }
}
@getRun('runrurnrun')
class banana {
    public logMsg(){
        (this as any).run()
    }
}
new apple().logMsg()
new banana().logMsg()

结果为:

成功啦
runrurnrun

类装饰器只有一个参数target,他是一个构造函数,上面两个方法示范了无参和传参的两种形式。

但是有人应该注意到我是怎么使用'新加'的函数的:(this as any).run(),这是因为ts不你呢个为装饰器提供类型保护,不知道我们已经修改了Class。

VnRpbYtrPvk9Wce

​ (直接使用就会直接报红)

所以我看到的实际类装饰器使用场景是子类中修改父类中已经存在的函数方法。

方法装饰器


方法装饰器在方法声明之前声明。方法装饰器应用于方法的属性描述符,可用于观察、修改或替换方法定义。方法装饰器不能用于声明文件、重载或任何其他环境上下文

方法装饰器会传入三个参数

  • target:要么是静态成员的类的构造函数,要么是实例成员的类原型。
  • propertyKey:方法名
  • descriptor:方法的描述对象

下面是一个使用例子:

function logMsg1(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log('原型:',target)
    console.log('方法名:',propertyKey)
    console.log('方法描述对象:',descriptor)
    msg='xXXXx,no ! 01'
}
let msg:string='my name is 01'
class Person{

    @logMsg1
    public msgName(){
        console.log(msg)
    }
}
new Person().msgName()

输出为:

原型: { msgName: [Function (anonymous)] }
方法名: msgName
方法描述对象: {
  value: [Function (anonymous)],
  writable: true,
  enumerable: true,
  configurable: true
}
xXXXx,no ! 01

多用于方法重载实现,给方法添加额外功能等。

属性装饰器


属性装饰器是在属性声明之前声明的。属性修饰符不能用于声明文件或任何其他环境上下文(例如在declare类中)。

属性装饰器的表达式将在运行时作为函数调用,具有以下两个参数:

  • 静态成员的类的构造函数,或实例成员的类原型。
  • 成员名称

可以用来修改成员的属性

需要注意的是:属性装饰器只能用于已为类声明了特定名称的属性。