1. 实现日志记录装饰器及 Calculator
类
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
const startTime = new Date();
console.log(`调用方法 ${propertyKey},传入参数:`, args);
const result = originalMethod.apply(this, args);
const endTime = new Date();
console.log(`方法 ${propertyKey} 返回值:`, result);
console.log(`方法 ${propertyKey} 调用耗时:`, endTime.getTime() - startTime.getTime(), 'ms');
return result;
};
return descriptor;
}
class Calculator {
@logMethod
add(a: number, b: number): number {
return a + b;
}
@logMethod
subtract(a: number, b: number): number {
return a - b;
}
}
2. 详细分析
- 日志记录装饰器
logMethod
:
- 接受三个参数:
target
(被装饰的类的原型对象)、propertyKey
(被装饰方法的名称)、descriptor
(被装饰方法的属性描述符)。
- 保存原始方法
originalMethod
。
- 重新定义
descriptor.value
,在新的函数中记录方法调用时间、传入参数,执行原始方法并记录返回值和调用耗时。
Calculator
类:
- 包含两个简单的数学运算方法
add
和 subtract
,使用 @logMethod
装饰器对这两个方法进行装饰,使得每次调用这两个方法时,都会打印出调用时间、传入参数以及返回值等日志信息。
3. 基于类的元编程(使用装饰器)的优势
- 代码复用:通过装饰器,可以将通用的功能(如日志记录、权限验证等)抽象出来,应用到多个不同的类方法上,避免在每个方法中重复编写相同的逻辑。
- 增强可维护性:将特定功能的代码集中在装饰器中,当需要修改功能时,只需要修改装饰器代码,而不需要在每个使用该功能的方法中逐一修改,提高了代码的可维护性。
- 提高代码可读性:使用装饰器可以使类的方法定义更加简洁明了,通过装饰器的名称可以直观地了解该方法具有哪些额外的功能。
4. 可能遇到的问题及解决方案
- 性能问题:由于装饰器会在运行时对方法进行包装,可能会带来一定的性能开销。解决方案是在性能敏感的代码中,谨慎使用装饰器,或者对装饰器进行优化,减少不必要的操作。
- 调试困难:装饰器会改变方法的执行逻辑,可能使得调试变得更加复杂。解决方案是在装饰器中添加详细的日志输出,便于在调试时追踪代码的执行流程。另外,现代的开发工具如 Visual Studio Code 对装饰器的调试支持越来越好,可以充分利用这些工具来辅助调试。
- 兼容性问题:装饰器是 ES7 的提案,在一些较老的 JavaScript 运行环境中可能不支持。解决方案是使用 Babel 等工具进行转码,将使用装饰器的代码转换为兼容老版本环境的代码。