
JavaScript 装饰器是一种特殊类型的声明,可以被附加到类声明、方法、访问器、属性或参数上。它使用一种注解形式的语法,通过在代码中添加 @expression 来“装饰”目标,从而修改其行为。虽然目前装饰器仍处于 ECMAScript 提案阶段(截至 2024 年为 Stage 3),但已被 TypeScript 和 Babel 等工具广泛支持。
类装饰器实现原理
类装饰器应用于类构造函数,可以用来监视、拦截或修改类定义。它的基本形式是一个函数,接收一个参数:类的构造函数。
注意: 类装饰器只能作用于类本身,不能用于类的方法或属性(除非结合其他机制)。类装饰器函数签名如下:
type ClassDecorator = (target: Function) => Function | void;
立即学习“Java免费学习笔记(深入)”;
示例:
function LogClass(target: Function) {
console.log('类被创建:', target.name);
}
@LogClass
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
}
// 输出:类被创建: Person
如果装饰器返回一个新的构造函数,它可以完全替换原始类。例如,可以扩展类的静态属性、注入元数据或代理构造过程。
方法装饰器实现原理
方法装饰器应用于类的方法,可以用来监听、修改或替换方法的定义。它不是直接操作方法逻辑,而是通过操作描述符(descriptor)来影响方法的行为。
方法装饰器函数签名如下:
type MethodDecorator = (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void | any;
- target:对于静态方法是类构造函数,对于实例方法是类的原型对象
- propertyKey:方法名称
- descriptor:该方法的属性描述符(可读、可写、可枚举、可配置等)
通过修改 descriptor.value 可以包装原方法,比如实现日志、权限检查、缓存等功能。
示例:实现一个简单的日志方法装饰器
function LogMethod(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`调用方法: ${propertyKey},参数:`, args);
const result = originalMethod.apply(this, args);
console.log(`方法返回值:`, result);
return result;
};
return descriptor;
}
class Calculator {
@LogMethod
add(a: number, b: number) {
return a + b;
}
}
const calc = new Calculator();
calc.add(2, 3);
// 输出:
// 调用方法: add,参数: [2, 3]
// 方法返回值: 5
装饰器如何工作:底层机制解析
装饰器本质上利用了 JavaScript 的 Object.defineProperty 和原型链机制。当应用装饰器时,编译器(如 TypeScript)会在类定义完成后自动调用装饰器函数,并传入相应参数。
- 类装饰器在类创建后立即执行,可修改构造函数或替换类
- 方法装饰器在类原型构建过程中被处理,通过 descriptor 修改方法特性
- 装饰器执行顺序:由内向外(多个装饰器时)、方法装饰器先于类装饰器执行
TypeScript 编译后的代码会将装饰器转换为对 __decorate 函数的调用,这个辅助函数负责按顺序应用装饰器并更新目标对象。
实际应用场景与注意事项
装饰器非常适合用于 AOP(面向切面编程),如日志记录、性能监控、权限控制、类型校验等横切关注点。
- 确保装饰器不破坏原有接口,避免副作用
- 谨慎修改 descriptor,尤其是 configurable 和 writable 属性
- 注意 this 指向问题,在包装方法时应使用 apply 或 bind 保持上下文
- 目前原生 JavaScript 尚未完全支持装饰器,需依赖构建工具(Babel、TS)
基本上就这些。理解装饰器的关键在于掌握它如何通过拦截和修改类或方法的定义过程,来实现非侵入式的功能增强。不复杂但容易忽略细节。










