TS装饰器

178 阅读3分钟

在 TypeScript 中,装饰器可以应用到类、属性、方法、方法参数和构造函数参数等不同的元素上,官方支持四种装饰器:类装饰器、属性装饰器、方法装饰器和参数装饰器。具体来说:

  1. 类装饰器:类装饰器用于修饰类的构造函数,并可以修改类的行为。类装饰器接收一个参数,指向被装饰的类所对应的构造函数。
  2. 属性装饰器:属性装饰器用于修饰类的属性,并可以修改属性的行为。属性装饰器接收两个参数,分别为被装饰的类的原型对象和被装饰的属性的名称。
  3. 方法装饰器:方法装饰器用于修饰类的方法,并可以修改方法的行为。方法装饰器接收三个参数,分别为被装饰的类的原型对象、方法名和方法的描述符。
  4. 参数装饰器:参数装饰器用于修饰类的构造函数、方法或属性中的参数,并可以修改参数的行为。参数装饰器接收三个参数,分别为被装饰的类的原型对象、方法名或属性名(如果是构造函数则为 undefined)以及参数在参数列表中的索引。

需要注意的是,以上四种装饰器是官方支持的 TypeScript 装饰器,不过这并不一定是 JavaScript 或其他 TypeScript 版本中唯一的选择,因为 ECMAScript 提案委员会正在讨论更多类型的装饰器,未来可能会有更多的装饰器被添加到语言规范中。

/**
* 类原型上函数参数装饰器
* @param target 类的原型 这里是Example.prototype
* @param context 修饰的函数的名称 这里是sum
* @param index 修饰的的函数参数位置索引 这里是第一个参数索引是0
*/
function plog(target, propertyKey, index) {
    // target === Example.prototype //true
    console.log('params decorator',target,propertyKey,index) // Example.prototype sum 0
}

/**
* 类原型上函数装饰器
* @param target 类的原型 这里是Example.prototype
* @param name 修饰的函数名称 这里是sum
* @param descriptor 修饰的函数的描述符 这里是{value:[function sum],writable:true,enumrable:false,configurable}
*/
function functionD(target,propertyKey,descriptor){
    console.log('function decorator',target,propertyKey,descriptor) 
}

/**
* 类装饰器
* @param target 修饰的类 这里是[class Example]
*/
function classD(target){
    console.log('class decorator',target)
}

/**
* 类构造函数参数装饰器
* @param target 修饰的类 这里是[class Example]
* @param context 构造函数不属于任何实例方法或属性 所以这里是undefined
* @param index 这里修饰的是第二个参数 所以这里索引是 1
*/
function clog(target, propertyKey, index){
    // 非方法装饰器的第二个参数 propertyKey(在构造函数中是 undefined,因为构造函数不属于任何实例方法或属性)
    console.log('contructor decorator',target,propertyKey,index)
}

/**
* 类构造函数参数装饰器补充  可以套一层 通过闭包通过传递参数的名称
* @param paramName
* @returns
*/
function clog2(paramName: string) {
    return function(target, propertyKey, index) {
        //console.log(`Logging ${paramName} at index ${index}`);
    }
}

/**
* 属性装饰器
* @param target 修饰的类 这里是[class Example]
* @param context 修饰的属性名称 这里是age
*/
function slog(target,propertyKey){
    console.log('property decortator',target,propertyKey)
}

@classD
class Example {
    @slog
    private static age:string;

    @functionD
    public sum(@plog a:number, b:number) {
        return a + b;
    }
    constructor(private a:string,@clog private x:symbol,@clog2("c") private c){}
}

最后打印顺序是

  1. params decorator
  2. function decorator
  3. property decortator
  4. contructor decorator
  5. class decorator

总结 从结果可以看出 类原型上的方法装饰器先执行 其次是静态属性 构造函数 最后是类本身 同一个函数里面 参数优先于函数执行 参数的执行顺序是从右到左的 它这个顺序是编译的时候固定的。 可以看一下TS编译成JS的结果 image.png