基本概念
装饰器用于增强类的功能。装饰器是一种函数,使用的时候写成 @+函数名,可以装饰类,类的属性,类的方法和类的属性存取器四种类型值。装饰器本质上就是编译时执行的函数
类的装饰
在下面的例子中,装饰器 @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 打印了方法传入的参数。
小结
本文先是介绍了装饰器的基本概念,再是介绍了类装饰器和方法装饰器。为了更加详细的介绍装饰器的行为,例举了两个实例作为补充说明。可以看出,给方法或类添加装饰器非常方便,使用装饰器后增强了方法或类的功能。