一、关键点
- 1、发生时间
装饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,装饰器能在编译阶段运行代码。也就是说,装饰器本质就是编译时执行的函数。
- 2、要求
只能在类里使用
- 3、本质
是一个函数
二、分类
类装饰器
目标
- 应用于类的构造函数
参数
- 第一个参数(也只有一个参数)target
类的构造函数作为其唯一的参数
属性装饰器
访问器装饰器
目标
- 应用于类的访问器(getter、setter)上
参数
- 第一个参数
-
- 静态方法:类的构造函数
- 实例方法:类的原型对象
- 第二个参数
-
- 属性名称
- 第三个参数
-
- 方法描述符对象
方法装饰器
目标
- 应用于类的方法上
参数
- 第一个参数target
-
- 静态方法static:类的构造函数
- 实例方法:类的原型对象
- 第二个参数name
-
- 被装饰的方法名称
- 第三个参数descriptor:PropertyDescriptor
-
- 方法描述符对象
参数装饰器
目标
- 应用在参数上
参数
- 第一个参数
-
- 静态方法:类的构造函数
- 实例方法:类的原型对象
- 第二个参数
-
- 方法名称
- 第三个参数
-
- 参数在函数参数列表中的索引
三、执行顺序
function d1(target: Function) {
console.log('----------->类装饰器-------------》d1');
console.log(target);
console.log(typeof target);
}
function d2(target: any, name: string) {
console.log('----------->属性装饰器-------------》d2');
console.log(typeof target, name);
}
function d3(target: any, name: string, descriptor: PropertyDescriptor) {
console.log('----------->访问器装饰器-------------》d3');
console.log(typeof target, name);
console.log(descriptor);
}
function d4(target: any, name: string, descriptor: PropertyDescriptor) {
console.log('----------->方法装饰器-------------》d4');
console.log(typeof target, name);
console.log(descriptor);
}
function d5(target: any, name: string, index: number) {
console.log('----------->参数装饰器-------------》d5');
console.log(typeof target, name);
console.log(index);
}
@d1
class HelloClass {
@d2
public age: number
@d2
static property1: number
@d3
get name() {
return 'lxq';
}
@d3
static get like() {
return '游泳'
}
@d4
public method1(@d5 x: number) {
}
@d4
public static method2(x: string, @d5 y: number) {
}
}
执行结果:
/**
* 执行顺序
* 类似洋葱圈
*/
// step1 : 实例装饰器
// 属性=>访问器=>参数=>方法
// step2 : 静态装饰器
// 属性=>访问器=>参数=>方法
// step3 : 类装饰
四、复合
/**
* 复合装饰器
* 执行顺序:类似洋葱圈
*/
function d11(target: Function) {
console.log('----------->类装饰器-------------》d11');
console.log(target);
console.log(typeof target);
}
@d1 @d11
class WorldClass { }
五、工厂
// 类的装饰器:类的继承
function InstanceClass<T extends { new(...agrs: any[]): {} }>(ThisConstructor: T) {
return class Contructor extends ThisConstructor {
constructor(...args: any[]) {
super(args);
}
sayHello() {
console.log('Hello everyone');
}
sayAge() {
console.log('my age is 31');
}
}
}
// 类的装饰器:实例属性扩展
function addProperty(propertyName: string) {
return (target: Function) => {
target.prototype.name = propertyName;
}
}
// 类的装饰器:静态属性扩展
function addStaticProperty(propertyName: string) {
return (target: any) => {
target.gender = propertyName;
}
}
@addStaticProperty('Man')
@addProperty('Cjet')
@InstanceClass
class Test {
constructor() { }
static gender:string;
name: string;
errorMsg: Error = new Error('方法未实现');
sayHello() {
throw this.errorMsg;
}
sayAge() {
throw this.errorMsg;
}
tellMe() {
this.sayHello();
this.sayAge();
}
}
const test = new Test();
console.log(test.name);
console.log(Test.gender);
test.tellMe();
六、工厂-方法装饰
// 方法装饰器
function log(target: Function, propertyName: string, descriptor: PropertyDescriptor) {
console.log('编译时:执行', target);
let oldValue = descriptor.value;
descriptor.value = function () {
console.log(`target🌶 : ${target}`);
console.log(`propertyName: ${propertyName} with`, arguments);
return oldValue.apply(this, arguments);
}
// return descriptor; // 可以省略
}
function readMoney(houseRent: string) {
return (target: Object, name: string, descriptor: PropertyDescriptor) => {
console.log('编译时:执行', target);
// console.log(name);
// console.log(descriptor);
let oldValue = descriptor.value;
descriptor.value = (...args: any[]) => {
return houseRent + "" + oldValue.apply(this, [...args, houseRent]);
}
// return descriptor; // 可以省略
}
}
class M {
@log
static add(a: number, b: number) {
return a + b;
}
@readMoney("$")
salary(baseSalary: number, Advanced: number,): number {
return baseSalary + Advanced;
}
@readMoney("¥")
earn(basePrice: number): number {
return basePrice;
}
}
const result = M.add(12, 13);
console.log(result);
const m = new M();
const salaryRes = m.salary(2000, 1000);
console.log(salaryRes);
const sarnRes = m.earn(15000);
console.log(sarnRes);