装饰器是TypeScript/JS Stage 3提案中用于类、方法、访问器、属性及参数的声明式增强机制,通过编译器或元编程在定义阶段注入逻辑,解耦日志、权限等横切关注点。
装饰器(decorators)在 typescript 和 javascript 的 stage 3 提案中,已支持对类、方法、访问器、属性甚至参数进行声明式增强。它不是运行时魔法,而是通过编译器或运行时元编程机制,在定义阶段注入逻辑,从而解耦横切关注点(如日志、权限、响应式、序列化等)。
类装饰器:控制类的创建与元信息
类装饰器接收构造函数作为唯一参数,可返回新构造函数以替换原类,或仅注入静态元数据。
- 用于注册组件(如框架中自动收集路由)、打标记(
@Deprecated)、添加静态字段或方法 - 配合
Reflect.metadata存储配置,例如:@Reflect.metadata('role', 'admin')class UserController {} - 注意:Stage 3 装饰器默认不修改原型链;若需重写类,必须显式返回新构造函数并保留原有原型关系
属性装饰器:拦截字段定义,实现响应式或验证
属性装饰器在类定义时执行,接收目标对象(类原型或构造函数)和属性名。它无法直接拦截后续赋值,但可配合 Object.defineProperty 或 Proxy 在初始化阶段接管。
- 常见用途:标记响应式字段(
@reactive)、设置默认值、绑定校验规则 - 示例(配合初始化逻辑):
function observable(target: any, key: string) {let value = target[key];Object.defineProperty(target, key, {get() { return value; },set(v) { console.log(`set ${key} =`, v); value = v; }});} - 注意:纯属性装饰器本身不触发 getter/setter —— 必须主动定义描述符,且仅对实例属性有效(非私有字段
#field)
方法与访问器装饰器:包装行为,注入前置/后置逻辑
方法装饰器接收目标对象、方法名、属性描述符;可修改描述符的 value(即原始函数),实现 AOP 风格增强。
- 典型场景:防抖(
@debounce(300))、权限检查(@requireRole('admin'))、性能监控(@measure) - 示例(带参数的装饰器工厂):
function throttle(ms: number) {return function(target: any, key: string, descriptor: PropertyDescriptor) {const original = descriptor.value;let timer: NodeJS.Timeout | null = null;descriptor.value = function(this: any, ...args: any[]) {if (!timer) {timer = setTimeout(() => { timer = null; }, ms);return original.apply(this, args);}};};} - 访问器(
get/set)装饰器同理,但需分别处理descriptor.get或descriptor.set
参数装饰器:标记依赖或类型信息(常配合 DI 容器)
参数装饰器不改变运行时行为,主要用于记录元数据,例如标识某个参数应从容器中解析(@Inject(UserService))或标注是否为可选(@Optional)。
- 它接收三个参数:目标对象、方法名(或
undefined表示构造函数)、参数索引 - 典型用法:
function Inject(token: any) {return function(target: any, method: string | undefined, index: number) {const params = Reflect.getMetadata('design:paramtypes', target, method) || [];Reflect.defineMetadata('inject:param', token, target, `${method || 'constructor'}:${index}`);};} - 需搭配 TypeScript 的
emitDecoratorMetadata编译选项才能获取类型信息










