JavaScript装饰器模式通过类装饰器语法糖和手动封装模拟,本质是不修改原类而动态增强行为,需实验性支持且依赖Babel或TypeScript编译,装饰器函数须为顶层声明,返回新类最安全,支持工厂函数传参定制,但不同于GoF装饰器模式的运行时组合思想。

JavaScript 中的装饰器模式不是靠 class 本身直接实现的,而是借助 类装饰器(Class Decorator)语法糖 + 手动封装逻辑 来模拟。它本质是“在不修改原类定义的前提下,动态增强其行为”,核心在于函数返回新类或改造原类。
装饰器语法需开启实验性支持
目前(ES2022+)装饰器仍是 Stage 3 提案,需使用 Babel(@babel/plugin-proposal-decorators)或 TypeScript 编译。原生环境暂未全面支持。启用后才能写:
@logClass
class UserService { ... }
注意:装饰器函数必须是顶层声明的函数,不能是箭头函数或内联函数。
类装饰器:包装并返回新类
类装饰器接收一个参数 —— 原类构造函数,可返回一个新类(或修改后的原类),从而拦截实例化、添加方法、注入属性等:
立即学习“Java免费学习笔记(深入)”;
- 返回新类是最安全的做法,避免污染原始类
- 可在新类中调用
super(...args)保证继承链正常 - 适合添加通用能力:日志、权限校验、性能统计
示例:自动记录实例创建日志
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function logClass(target) {
return class extends target {
constructor(...args) {
console.log(`[Decorator] ${target.name} is being instantiated`);
super(...args);
}
};
}
<p>@logClass
class ApiClient {
constructor(url) {
this.url = url;
}
}</p><p>new ApiClient('/api/users'); // 输出日志 + 正常创建实例
装饰器工厂:支持传参定制行为
用闭包返回装饰器函数,就能传入配置,让装饰逻辑更灵活:
- 外层函数接收配置项,内层函数接收目标类
- 常见于带开关、前缀、超时阈值等场景
- TypeScript 中类型提示更清晰
示例:为类方法统一加防抖(需配合方法装饰器,此处仅展示类级控制开关)
function withDebounce(wait = 300) {
return function (target) {
return class extends target {
constructor(...args) {
super(...args);
// 可在此对原型方法做批量包装,如遍历 this.constructor.prototype
}
};
};
}
<p>@withDebounce(500)
class SearchService {
search(query) { /<em> ... </em>/ }
}
注意与真正“设计模式”的区别
JS 装饰器语法 ≠ GoF 装饰器模式的直接映射:
- GoF 装饰器强调“组合优于继承”,通过包装对象动态添加职责(如
new LoggingDecorator(new ApiClient())) - JS 类装饰器更像“元编程增强”,作用于类定义阶段,属于编译/加载时行为
- 若需运行时灵活装饰,仍应手动实现装饰器类或高阶函数
真正面向对象风格的装饰器模式可这样写(无需装饰器语法):
class LoggingDecorator {
constructor(wrapped) {
this.wrapped = wrapped;
}
request(...args) {
console.log('Logging before request');
const result = this.wrapped.request(...args);
console.log('Logging after request');
return result;
}
}
<p>const client = new LoggingDecorator(new ApiClient());
client.request('/users');
不复杂但容易忽略:装饰器是语法糖,底层靠函数转换;想用好,关键在理解“谁被装饰、何时执行、返回什么”。

















