装饰器是JavaScript中一种用于在不修改原有代码结构的前提下,为类、类的方法、属性等添加额外功能的设计模式实现,它本质上是一个函数,通过特殊的语法糖形式作用于目标对象,在编译或运行时对目标进行包装或增强。

装饰器的基本语法
装饰器使用@符号作为前缀,紧跟在要修饰的目标之前。根据修饰的目标不同,装饰器的参数和返回值也有不同的要求。目前装饰器还处于ECMAScript的提案阶段,部分环境需要开启对应配置才能使用,比如TypeScript中需要开启experimentalDecorators配置,Babel中需要安装对应的装饰器插件。
类装饰器
类装饰器应用于类本身,接收一个参数即被装饰的类构造函数,可以修改类的构造函数或者为类添加静态属性、原型方法等。
// 定义一个简单的类装饰器,为类添加一个静态属性
function addStaticProp(target) {
target.version = "1.0.0";
return target;
}
// 使用装饰器修饰类
@addStaticProp
class User {
constructor(name) {
this.name = name;
}
}
console.log(User.version); // 输出 1.0.0
方法装饰器
方法装饰器应用于类的原型方法,接收三个参数:目标类的原型对象、方法名、方法描述符。可以通过修改描述符来改变方法的行为,比如添加日志、权限校验等功能。
// 定义一个方法装饰器,打印方法执行前后的日志
function log(target, methodName, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`方法 ${methodName} 开始执行,参数:`, args);
const result = originalMethod.apply(this, args);
console.log(`方法 ${methodName} 执行结束,结果:`, result);
return result;
};
return descriptor;
}
class Calculator {
@log
add(a, b) {
return a + b;
}
}
const calc = new Calculator();
calc.add(1, 2);
// 输出:
// 方法 add 开始执行,参数: [1, 2]
// 方法 add 执行结束,结果: 3
属性装饰器
属性装饰器应用于类的属性,接收两个参数:目标类的原型对象、属性名,通常用来修改属性的描述符,比如设置属性是否可枚举、是否可写等。
// 定义一个属性装饰器,设置属性为只读
function readonly(target, propertyName) {
Object.defineProperty(target, propertyName, {
writable: false
});
}
class Person {
@readonly
name = "张三";
}
const person = new Person();
person.name = "李四"; // 严格模式下会报错,非严格模式下赋值无效
console.log(person.name); // 输出 张三
装饰器的常见使用场景
- 日志记录:为方法添加执行日志,无需在每个方法内部重复编写日志代码,提升代码复用性。
- 权限校验:在接口方法前添加权限校验装饰器,判断用户是否有权限执行该操作,统一处理权限逻辑。
- 缓存处理:为计算类方法添加缓存装饰器,相同参数调用时直接返回缓存结果,减少重复计算。
- 参数校验:为方法参数添加校验规则,在方法执行前校验参数合法性,不合法则直接抛出错误。
装饰器的实现原理
装饰器的本质是一个高阶函数,它接收目标对象作为参数,对目标对象进行处理后返回新的对象或者直接修改原对象。以方法装饰器为例,它的执行逻辑可以近似理解为下面的普通函数调用形式:
// 普通函数形式实现方法装饰逻辑
function log(target, methodName, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`方法 ${methodName} 开始执行`);
return originalMethod.apply(this, args);
};
return descriptor;
}
class Demo {
sayHello() {
console.log("Hello");
}
}
// 手动应用装饰逻辑,等价于 @log 语法
const descriptor = Object.getOwnPropertyDescriptor(Demo.prototype, "sayHello");
const newDescriptor = log(Demo.prototype, "sayHello", descriptor);
Object.defineProperty(Demo.prototype, "sayHello", newDescriptor);
const demo = new Demo();
demo.sayHello();
// 输出:方法 sayHello 开始执行
// 输出:Hello
使用装饰器的注意事项
- 装饰器的执行顺序是从下往上、从内到外,多个装饰器作用于同一个目标时,先执行离目标最近的装饰器。
- 目前原生JavaScript环境对装饰器的支持还不完善,实际项目中使用通常需要借助TypeScript或者Babel等工具进行转译。
- 装饰器只能用于类、类的方法和类的属性,不能用于普通函数,因为普通函数存在变量提升问题,装饰器无法正确绑定目标。
- 不要在装饰器中执行过于复杂的逻辑,避免影响代码的执行性能和可读性。
装饰器是一种非常灵活的代码增强方式,合理使用可以减少重复代码,让业务逻辑更加清晰,但是也需要根据项目实际情况选择是否使用,避免过度设计。
JavaScript装饰器decoratorES6修改时间:2026-06-16 04:30:16