class 语法虽不原生支持装饰器,但可通过封装函数或类模拟其逻辑;es2022 引入 class 装饰器提案,仍需 babel 或 typescript 编译;可用 class 实现函数装饰、方法节流等增强行为。

Class 语法本身不直接支持装饰器(Decorator)语法,但可以用 class 实现装饰器的底层逻辑——即通过封装函数或类,动态增强其行为。ES2022 正式引入了 class 装饰器提案(Stage 3),但目前主流浏览器和 Node.js 仍需 Babel 或 TypeScript 编译支持。不过,我们可以用 class 模拟装饰器的核心思想:接收目标、修改元数据或包装方法。
用 Class 封装函数装饰逻辑
装饰器本质是高阶函数:接收原函数,返回新函数。用 class 实现时,可将“装饰行为”封装为类实例,再通过实例的 wrap 或 apply 方法介入调用过程。
- 定义一个装饰器类,构造时接收配置(如日志开关、重试次数)
- 提供
decorate(fn)方法,返回包装后的新函数 - 在包装函数中插入前置/后置逻辑,或捕获异常
例如实现一个带日志的装饰器类:
class LoggerDecorator {constructor(options = {}) {
this.enabled = options.enabled ?? true;
}
decorate(fn) {
return function(...args) {
if (this.enabled) console.log(`[LOG] Calling ${fn.name}`);
const result = fn.apply(this, args);
if (this.enabled) console.log(`[LOG] Done ${fn.name}`);
return result;
};
}
}
模拟类装饰器:增强类或方法的元信息
虽然不能直接用 @ 语法(需编译器支持),但可通过 class 手动“应用”装饰逻辑到目标类或方法上。关键是操作原型、描述符或静态元数据。
- 对类方法装饰:获取目标方法的 descriptor,替换
value为包装函数 - 对整个类装饰:修改类的原型、添加静态属性、或返回新 class
- 可配合
WeakMap存储私有状态,避免污染目标对象
示例:一个限制方法调用频率的装饰器类:
constructor(ms = 1000) {
this.ms = ms;
this.lastCall = new WeakMap();
}
decorate(target, key, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
const now = Date.now();
const last = this.lastCall.get(original) || 0;
if (now - last this.lastCall.set(original, now);
return original.apply(this, args);
};
return descriptor;
}
}
配合 TypeScript 使用更自然
TypeScript 原生支持装饰器语法,并允许装饰器类实现接口 ClassDecorator、MethodDecorator 等。此时 class 不仅是工具,更是类型安全的装饰器工厂。
- 定义装饰器类时实现对应装饰器接口,IDE 和编译器能校验签名
- 利用泛型参数约束目标类型,比如只装饰返回 Promise 的方法
- 结合 Reflect Metadata API 存储设计时元数据(如路由路径、权限角色)
例如定义一个可配置的权限检查装饰器类:
class AuthDecorator implements MethodDecorator {constructor(private role: string) {}
__decorate(target, propertyKey, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
if (!this.user?.roles?.includes(this.role)) {
throw new Error('Access denied');
}
return original.apply(this, args);
};
}
}
注意事项与兼容性
纯 JavaScript 运行时无法解析 @decorator 语法,必须借助构建工具。用 class 实现装饰逻辑时,需注意:
- 装饰器类不应依赖执行顺序以外的状态,保证可复用性
- 避免在装饰过程中修改原始 descriptor 的不可枚举属性(如
writable),否则可能破坏继承 - 若用于 React 组件等框架环境,需确认框架是否支持自定义装饰器(如 MobX 支持,React 官方不推荐)
- 生产环境建议优先使用标准 Hooks 或高阶组件替代装饰器,更易调试和测试
不复杂但容易忽略:装饰器类只是组织逻辑的一种方式,核心仍是函数组合与元编程思维。











