TS装饰器介绍

126 阅读1分钟

访问调试

/*
* 类装饰器
* @params constructor 构造器
*/ 
function addAge(constructor: Function) {
    // console.log(constructor)
    constructor.prototype.age = '18';
}

/*
* 方法装饰器
* @params target 对象的原型
* @params propertyKey 方法的名称
* @params description 方法的属性描述符
* 这三个属性实际就是`Object.defineProperty`的三个参数
*/ 
function method(target: any, propertyKey: string, description: PropertyDescriptor) {
    console.log(target)
    console.log(propertyKey)
    console.log(description)
}
// 属性装饰器,比方法少一个description
function property(target: any, propertyKey: string) {
    console.log(target, propertyKey)
    target.propertyKey = 'hahhaa'
}
// 参数装饰器
function logParameter(target: any, propertyName: string, index: number) {
    console.log(target)
    console.log(propertyName)
    console.log(index)
}

@addAge
class Person{
  @property
  name: string;
  age!: number;
  constructor() {
    this.name = 'huihui';
  }
  @method
  sayName() {
      console.log('say')
      return 'say'
  }
  doing(@logParameter work: string) {
      console.log(work)
  }
}

let person = new Person();

// console.log(person.age);
person.doing('homework')

// 执行顺序
// 当多个装饰器应用于一个声明上,将由上至下依次对装饰器表达式求值,求值的结果会被当作函数,由下至上依次调用,例如如下:
function f() {
    console.log("f(): evaluated");
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

function g() {
    console.log("g(): evaluated");
    return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("g(): called");
    }
}

class C {
    @f()
    @g()
    method() {}
}

// 输出
// f(): evaluated
// g(): evaluated
// g(): called
// f(): called

总结

可以看到,使用装饰器存在两个显著的优点:

  • 代码可读性变强了,装饰器命名相当于一个注释
  • 在不改变原有代码情况下,对原来功能进行扩展

后面的使用场景中,借助装饰器的特性,除了提高可读性之后,针对已经存在的类,可以通过装饰器的特性,在不改变原有代码情况下,对原来功能进行扩展