解析装饰器语法

129 阅读2分钟

基本概念

装饰器用于增强类的功能。装饰器是一种函数,使用的时候写成 @+函数名,可以装饰类,类的属性,类的方法和类的属性存取器四种类型值。装饰器本质上就是编译时执行的函数

类的装饰

在下面的例子中,装饰器 @strengthen 可以给类 TestClass 增加实例属性 canMakeMoney,实例方法 speakEnglish 和静态属性 isLiving。

装饰器函数的参数 target 就是目标类,再装饰器函数再包一层就可以实现装饰器行为的自定义,例子中演示了增加布尔值和增加对象的场景。

const skills = {
  speakEnglish() {
    console.log("hello,decorator"); // hello,decorator
  },
};

@strengthen(true, false, skills)
class TestClass {
  static isLiving: boolean;
  canMakeMoney: boolean;

  speakEnglish(): any {
    throw new Error("Method not implemented.");
  }
}

function strengthen(isLiving, canMakeMoney, methods) {
  return function (target) {
    target.isLiving = isLiving;
    target.prototype.canMakeMoney = canMakeMoney;
    Object.assign(target.prototype, methods);
  };
}

console.log(TestClass.isLiving); // true
const ttt = new TestClass();
console.log(ttt.canMakeMoney); // false
ttt.speakEnglish();

方法的装饰

方法装饰器中,装饰器函数接受三个参数,第一个是类的原型对象,第二个是方法名,第三个是对应的描述对象。装饰器具有注释的作用,可以看到 MyMath 类里面的 add 方法会在执行的时候打印 log。

class MyMath {
  @log
  add(a, b) {
    return a + b;
  }
}

function log(target, name, descriptor) {
  let oldValue = descriptor.value;

  descriptor.value = function () {
    console.log(`Calling ${name} with`, arguments); // Calling add with [Arguments] { '0': 2, '1': 4 }
    return oldValue.apply(this, arguments);
  };

  return descriptor;
}

const math = new MyMath();

math.add(2, 4);

上面的例子中,MyMath 类里面有一个 add 方法,通过 @log 装饰器可以在 add 方法执行的时候打印日志。具体来说,在装饰器函数 log 中,修改了 descriptor.value,使得在获取 descriptor.value 的值的时候使用 console.log 打印了方法传入的参数。

小结

本文先是介绍了装饰器的基本概念,再是介绍了类装饰器和方法装饰器。为了更加详细的介绍装饰器的行为,例举了两个实例作为补充说明。可以看出,给方法或类添加装饰器非常方便,使用装饰器后增强了方法或类的功能。

参考链接: es6.ruanyifeng.com/#docs/decor…