装饰器是JavaScript中基于Object.defineProperty的元编程工具,通过在定义阶段拦截类或方法并返回增强后的构造函数或属性描述符来实现功能增强,目前需借助TypeScript或Babel转译支持。

JavaScript 中的装饰器是一种元编程工具,本质是接收目标信息并返回增强后定义的函数。它不修改原始代码,而是通过拦截类或方法的定义过程,在运行时动态注入新逻辑,从而实现功能增强。
装饰器是怎么工作的
装饰器不是语法糖,而是基于 Object.defineProperty 的底层机制。当你写 @log 时,JavaScript 实际上是在类或方法被定义的那一刻,调用该装饰器函数,并传入关键元信息:
- 类装饰器 → 接收构造函数(
target) - 方法装饰器 → 接收原型对象、方法名、属性描述符(
target, propertyKey, descriptor) - 属性装饰器 → 接收原型对象和属性名
- 参数装饰器 → 接收原型、方法名、参数索引
装饰器函数可修改 descriptor.value(如重写方法体)、添加静态属性、冻结类结构,甚至替换整个构造函数——所有操作都发生在定义阶段,而非调用阶段。
为什么能增强类或方法功能
增强能力来自两个关键设计:
立即学习“Java免费学习笔记(深入)”;
- 运行时介入定义流程:装饰器在类/方法被创建但尚未使用时执行,此时可以安全地读取、包装、替换其行为,比如把原方法包裹进日志、防抖或权限校验逻辑中
-
返回新描述符或构造器:方法装饰器必须返回一个
PropertyDescriptor;类装饰器可返回新构造函数。这种“返回即生效”的机制,让增强结果直接成为最终暴露给使用者的对象
例如,@debounce(300) 并不是给方法加个标记,而是立刻生成一个带定时器控制的新方法体,并用它替换了原始方法。
它和普通高阶函数有什么区别
装饰器语法(@)是声明式写法,但语义等价于手动调用高阶函数:
- 普通高阶函数:你需要显式赋值,比如
const debounced = debounce(300)(fn) - 装饰器:你只需在定义处标注
@debounce(300),编译器或运行时自动完成拦截、调用、重定义全过程 - 优势在于解耦——业务方法保持干净,横切逻辑(日志、缓存、校验)集中管理、统一复用
目前能用吗?要注意什么
装饰器仍是 ECMAScript 第3阶段提案(截至2025年12月),未被浏览器原生支持,但可通过以下方式实际使用:
- TypeScript:启用
"experimentalDecorators": true和"emitDecoratorMetadata": true - Babel:配合
@babel/plugin-proposal-decorators插件 - 注意兼容性:不能直接在 Node.js 或 Chrome 控制台运行带
@的代码,需先转译
它的价值不在“是否标准”,而在于提供了一种清晰、可组合、可复用的增强范式——尤其适合框架开发与大型应用的横切关注点治理。











