JavaScript装饰器仍为Stage 3提案,浏览器原生不支持,需Babel或TypeScript编译;仅适用于类及成员,不支持普通函数;方法装饰器接收target、propertyKey、descriptor三参数,在类定义时同步执行。

JavaScript 的装饰器目前仍是 Stage 3 提案,未被正式纳入标准,所有浏览器原生都不支持,必须通过 Babel(@babel/plugin-proposal-decorators)或 TypeScript 编译才能运行。
装饰器只能用在类和类成员上,不能用于普通函数
这是最容易混淆的一点:你不能写 @log function foo() {} —— 这会直接报语法错误。装饰器的语法糖只作用于类声明、方法、访问器、属性(仅 TS 支持字段装饰器)和参数(实验性,极少用)。
实际可用的场景只有:
- 类本身:
@sealed class MyClass {} - 类方法:
class C { @readonly method() {} } - 类 getter/setter:
get @cached value() {} - TypeScript 中的字段:
class C { @observable name = 'a'; }(需启用useDefineForClassFields)
注意:Babel 默认不支持字段装饰器,TypeScript 需配置 "experimentalDecorators": true 和 "useDefineForClassFields": true 才能解析 @decorator field 语法。
立即学习“Java免费学习笔记(深入)”;
装饰器函数接收什么参数?执行时机在哪?
方法装饰器(最常用)接收三个参数:target(原型对象)、propertyKey(方法名字符串)、descriptor(属性描述符)。它在类定义阶段执行,不是在方法调用时。
例如这个日志装饰器:
function log(target, propertyKey, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args) {
console.log(`Calling ${String(propertyKey)} with`, args);
return original.apply(this, args);
};
return descriptor;
}
class Calculator {
@log
add(a, b) {
return a + b;
}
}
关键点:
-
descriptor.value是原始方法,必须返回修改后的descriptor才生效 - 不要漏掉
return descriptor,否则方法会被设为undefined - 装饰器函数本身是同步执行的,在模块加载时就完成包装,不是懒加载
Babel 和 TypeScript 的装饰器行为不一致
这是线上出问题的高发区。Babel 的装饰器默认使用「legacy」模式(类似 TS 早期行为),而 TypeScript 5.0+ 默认使用「2023」语义(更贴近提案最终方向),二者对字段初始化、this 绑定、装饰器执行顺序的处理不同。
若你在 Babel 中用了 @init 装饰字段,又在 TS 中编译,大概率会发现值没被正确赋值。解决办法:
- Babel 配置中显式指定
{"version": "2023"}(需 Babel 7.23+) - TypeScript 中保持
"experimentalDecorators": true,但避免混合使用字段装饰器和复杂初始化逻辑 - 生产环境尽量避免依赖装饰器做关键初始化,改用构造函数或
init()显式调用
装饰器不是语法糖的终点,而是元编程的入口——但它依赖工具链、版本对齐和明确的执行时序。一旦跨环境部署,@ 符号背后藏着的其实是两套编译器对同一份提案的不同解读。











