javascript 的 class 语法本身不原生支持装饰器,需通过 typescript 或 babel 实验性插件启用;装饰器是以 @ 开头的函数,用于增强类、方法等,接收目标对象、名称、描述符等参数并返回修改结果。

JavaScript 的 class 语法本身不原生支持装饰器(Decorator),但可通过 TypeScript 或启用实验性 Babel 插件(如 @babel/plugin-proposal-decorators)使用。装饰器是用于“增强”类、方法、属性或访问器的语法糖,本质是函数,接收目标对象、成员名、描述符等参数,返回修改后的描述符或新值。
装饰器基础写法与启用方式
装饰器以 @ 开头,放在类、方法或属性声明前。需注意:
- TypeScript 中默认支持,需在
tsconfig.json中开启"experimentalDecorators": true和"emitDecoratorMetadata": true(后者用于反射元数据) - 纯 JavaScript 需用 Babel:安装
@babel/plugin-proposal-decorators,并在.babelrc中配置{"legacy": false}(推荐 Stage 3 提案语法) - 装饰器执行顺序:类装饰器最后执行;同级多个装饰器从上到下求值,从下到上应用(类似函数组合)
类装饰器:拦截并改造整个类
类装饰器接收三个参数:constructor(类本身)、context(可选,含元数据信息,新提案中替代旧 descriptor 参数)。可用于日志、注入、重写原型等:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
function logClass(target) {
console.log('类被定义:', target.name);
// 可返回新构造函数,实现类替换
return class extends target {
constructor(...args) {
super(...args);
console.log(`${target.name} 实例已创建`);
}
};
}
@logClass
class User {
name = 'Alice';
}
new User(); // 输出:类被定义: User → User 实例已创建
方法装饰器:增强或拦截方法行为
方法装饰器接收:target(原型对象)、propertyKey(方法名)、descriptor(属性描述符)。常用于权限校验、缓存、日志:
- 修改
descriptor.value可包装原方法(如加 try-catch) - 设置
descriptor.writable = false可冻结方法 - 结合
Reflect.getMetadata可读取自定义元数据
function readonly(target, key, descriptor) {
descriptor.writable = false;
return descriptor;
}
function logExecution(target, key, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args) {
console.log(`调用 ${key},参数:`, args);
const result = original.apply(this, args);
console.log(`${key} 返回:`, result);
return result;
};
return descriptor;
}
class Calculator {
@readonly
@logExecution
add(a, b) {
return a + b;
}
}
实际项目中的典型用法
装饰器不是语法糖而是能力扩展工具,在框架中广泛使用:
- Angular:@Component、@Input、@Output 都是类/属性装饰器,用于声明元数据
- NestJS:@Controller、@Get、@UseGuards 等统一管理路由与中间件
- 自定义验证:给字段加 @Required、@MinLength(6),配合反射在实例化时校验
- 自动注册:@Service 装饰器将类加入 DI 容器,无需手动 import 注册
注意:装饰器目前仍是 Stage 3 提案,浏览器原生不支持,生产环境务必通过编译转换;避免过度抽象,优先保证可读性与调试友好性。










