如何实现TypeScript类装饰器自动为所有方法添加计时功能
TypeScript 类装饰器自动为普通方法添加计时日志
1. 单个方法的计时装饰器 TimeDebug
先确认单个方法的计时装饰器实现,这是核心基础:
function TimeDebug(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const start = performance.now(); const result = originalMethod.apply(this, args); const end = performance.now(); console.log(`方法 ${propertyKey} 执行耗时: ${(end - start).toFixed(2)}ms`); return result; }; return descriptor; }
2. 类装饰器 TimeMethods 实现
接下来实现类装饰器,自动遍历类的所有普通方法,排除 getter、属性、构造函数等,给符合条件的方法批量加上TimeDebug:
function TimeMethods() { return function (constructor: Function) { // 遍历类原型上的所有属性名 Object.getOwnPropertyNames(constructor.prototype).forEach((propertyKey) => { const descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, propertyKey); // 过滤规则:是普通方法(有value属性且为函数)、不是构造函数 if (descriptor && typeof descriptor.value === 'function' && propertyKey !== 'constructor') { // 给目标方法应用计时装饰器 TimeDebug(constructor.prototype, propertyKey, descriptor); // 更新原型上的方法描述符 Object.defineProperty(constructor.prototype, propertyKey, descriptor); } }); }; }
3. 使用示例
用给定的MyClass测试效果:
@TimeMethods() class MyClass { private _foo: string = 'bar'; get foo() { return this._foo; } printX(x: string) { console.log(`输出: ${x}`); // 模拟耗时操作 for (let i = 0; i < 10000000; i++) {} } add(a: number, b: number): number { // 模拟耗时操作 for (let i = 0; i < 5000000; i++) {} return a + b; } } // 测试执行 const instance = new MyClass(); instance.printX('Hello TypeScript'); console.log(instance.add(10, 20)); console.log(instance.foo); // getter不会被添加计时日志
4. 扩展:排除指定普通方法
如果需要跳过某些不需要计时的普通方法,可以给TimeMethods添加参数,指定排除列表:
function TimeMethods(excludeMethods: string[] = []) { return function (constructor: Function) { Object.getOwnPropertyNames(constructor.prototype).forEach((propertyKey) => { // 跳过指定排除的方法 if (excludeMethods.includes(propertyKey)) return; const descriptor = Object.getOwnPropertyDescriptor(constructor.prototype, propertyKey); if (descriptor && typeof descriptor.value === 'function' && propertyKey !== 'constructor') { TimeDebug(constructor.prototype, propertyKey, descriptor); Object.defineProperty(constructor.prototype, propertyKey, descriptor); } }); }; } // 使用时排除add方法 @TimeMethods(['add']) class MyClass { // ... 类内容同上 }
关键逻辑说明
- 类装饰器通过遍历类的
prototype属性,获取每个属性的描述符,以此区分普通方法和getter(getter的描述符没有value,而是有get属性)。 - 自动跳过
constructor,避免修改类的构造逻辑,确保只有业务普通方法被添加计时日志。
内容的提问来源于stack exchange,提问作者Wouter Vandenputte
相关产品推荐
相关产品推荐

