定义
装饰器(Decorator)是一种特殊的语法,用于修改类、方法、属性或参数的行为。装饰器在很多语言中都有支持,JavaScript 在 ES6 中也引入了类装饰器,并在 TypeScript 中得到了广泛使用。装饰器语法可以增强类或其成员的功能,使代码更具可维护性和可扩展性。
:::danger
装饰器目前属于【实验性语法】,因此在项目中使用可能需要用到对应插件进行解析、转换
:::
基本语法
装饰器的基本形式是一个函数,它接收目标对象、属性名称等参数,并可以修改目标或属性的行为。
类装饰器
类装饰器是作用于整个类的,它接收类的构造函数作为参数,并可以对类进行修改或扩展。
function LogClass(target: Function) {
console.log(`Class decorated: ${target.name}`);
}
@LogClass
class MyClass {
constructor() {
console.log("MyClass instantiated");
}
}
// 输出:Class decorated: MyClass
方法装饰器
方法装饰器用于修改类中方法的行为。它接收三个参数:目标对象、属性名称以及方法的属性描述符。
function LogMethod(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`Method ${propertyKey} called with args: ${args}`);
return originalMethod.apply(this, args);
};
}
class MyClass {
@LogMethod
sayHello(name: string) {
console.log(`Hello, ${name}`);
}
}
const myClass = new MyClass();
myClass.sayHello("John");
// 输出:Method sayHello called with args: John
// 输出:Hello, John
属性装饰器
属性装饰器用于修改类属性的行为,它接收目标对象和属性名称作为参数。
function LogProperty(target: any, propertyKey: string) {
let value = target[propertyKey];
const getter = () => {
console.log(`Get value of ${propertyKey}: ${value}`);
return value;
};
const setter = (newValue: any) => {
console.log(`Set value of ${propertyKey}: ${newValue}`);
value = newValue;
};
Object.defineProperty(target, propertyKey, {
get: getter,
set: setter,
enumerable: true,
configurable: true,
});
}
class MyClass {
@LogProperty
name: string;
constructor(name: string) {
this.name = name;
}
}
const myClass = new MyClass("Alice");
// 输出:Set value of name: Alice
myClass.name = "Bob";
// 输出:Set value of name: Bob
console.log(myClass.name);
// 输出:Get value of name: Bob
// 输出:Bob
参数装饰器
参数装饰器用于修改方法参数的行为,接收目标对象、方法名称和参数索引作为参数。
function LogParameter(
target: any,
propertyKey: string,
parameterIndex: number
) {
console.log(
`Parameter ${parameterIndex} in method ${propertyKey} is being decorated`
);
}
class MyClass {
greet(@LogParameter name: string) {
console.log(`Hello, ${name}`);
}
}
// 输出:Parameter 0 in method greet is being decorated
访问装饰器
访问器装饰器可以装饰类的 getter 和 setter,用法类似于方法装饰器。
function LogAccessor(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalGet = descriptor.get;
descriptor.get = function () {
console.log(`Getting value of ${propertyKey}`);
return originalGet?.apply(this);
};
}
class MyClass {
private _value: string = "default";
@LogAccessor
get value() {
return this._value;
}
set value(newValue: string) {
this._value = newValue;
}
}
const myClass = new MyClass();
console.log(myClass.value);
// 输出:Getting value of value
// 输出:default
TperScript 装饰器配置
为了在 TypeScript 中使用装饰器,需要在 tsconfig.json 中启用装饰器相关配置:
{
"compilerOptions": {
"experimentalDecorators": true, // 启用装饰器语法
"emitDecoratorMetadata": true // 启用元数据反射
}
}
装饰器组合
多个装饰器可以叠加在一起使用,执行顺序为从下到上:
function First() {
console.log("First Decorator");
return function (target: any) {
console.log("First decorator executed");
};
}
function Second() {
console.log("Second Decorator");
return function (target: any) {
console.log("Second decorator executed");
};
}
@First()
@Second()
class MyClass {}
实际应用场景
- 日志记录:可以通过装饰器自动记录类、方法的调用和参数。
- 权限检查:在执行方法前检查权限,或者验证用户是否有权限执行某些操作。
- 缓存:为某些方法结果添加缓存逻辑,减少不必要的重复计算。
- 依赖注入:在 Angular、NestJS 等框架中,装饰器常用于依赖注入,自动为类的构造函数注入依赖项。