JavaScript类方法装饰器需通过TypeScript或Babel启用,接收target、propertyKey、descriptor三参数,可动态包装方法实现日志、计时、权限校验等;其在类定义时执行,不可访问this实例属性,但可在包装函数中访问。

JavaScript 的 Class 语法本身不原生支持装饰器(Decorator),但可通过 TypeScript 或 Babel(配合 @babel/plugin-proposal-decorators)启用实验性装饰器功能。在该前提下,**类方法装饰器**可在定义时动态拦截、包装或替换方法逻辑,实现运行前/后增强、权限校验、日志记录等。
方法装饰器的基本结构与参数
方法装饰器是一个函数,接收三个参数:
-
target:如果是静态方法,为类构造函数;否则为类的原型对象(
prototype) - propertyKey:方法名(字符串或 Symbol)
-
descriptor:属性描述符对象,含
value(原方法)、enumerable、configurable、writable等
通过修改 descriptor.value,就能替换原始方法;也可返回新 descriptor 来覆盖默认行为。
动态包装方法:添加日志与计时
以下装饰器在调用目标方法前后自动打印日志并统计耗时:
function logAndTime(target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.time(`[log] ${String(propertyKey)}`);
const result = originalMethod.apply(this, args);
console.timeEnd(`[log] ${String(propertyKey)}`);
return result;
};
return descriptor;
}
class Calculator {
@logAndTime
add(a, b) {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3); // 控制台输出带计时的日志
运行时条件性修改:基于环境或参数拦截
装饰器可结合闭包或外部状态,在实例化后仍能动态响应变化。例如,只在开发环境生效的调试装饰器:
function debugOnly(enabled = true) {
return function(target, propertyKey, descriptor) {
if (!enabled || process.env.NODE_ENV !== 'development') {
return descriptor; // 不做任何修改
}
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`? Debug: calling ${String(propertyKey)} with`, args);
return original.apply(this, args);
};
return descriptor;
};
}
class ApiClient {
@debugOnly(true)
fetchUser(id) {
return Promise.resolve({ id, name: 'Alice' });
}
}
注意兼容性与执行时机
装饰器在类定义阶段(即模块加载时)执行,而非实例创建时。这意味着:
- 无法直接访问
this实例属性(因尚未实例化),但可在包装函数中访问 - Babel 默认使用 legacy 装饰器提案(类似 TypeScript 早期版本),行为与 Stage 3 提案略有差异,需统一配置
- 若需修改类自身(如增加静态方法或字段),应使用 类装饰器,而非方法装饰器
目前(2024),Stage 3 装饰器提案已进入 Final 阶段,主流构建工具均支持,但需确保转译配置启用最新装饰器语法(如 Babel 设置 legacy: false)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











