/*
* 类装饰器
* @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
总结
可以看到,使用装饰器存在两个显著的优点:
- 代码可读性变强了,装饰器命名相当于一个注释
- 在不改变原有代码情况下,对原来功能进行扩展
后面的使用场景中,借助装饰器的特性,除了提高可读性之后,针对已经存在的类,可以通过装饰器的特性,在不改变原有代码情况下,对原来功能进行扩展