装饰器
装饰器是一种特殊的函数,它可以用来修改类的行为。装饰器的语法是
@expression,其中expression是一个函数,它会被应用到被装饰的函数上。
类装饰器
typescript
// 类装饰器示例
function logClass(constructor: Function) {
// 输出类的构造信息
console.log(`Constructing a new ${constructor.name}`);
}
@logClass // 应用类装饰器
class MyClass {
constructor() {
console.log("Hello, world!"); // 构造函数中的逻辑
}
}
// 输出:
// Constructing a new MyClass
// Hello, world!方法装饰器
typescript
// 方法装饰器示例
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value; // 保存原始方法
descriptor.value = function (...args: any[]) {
// 输出方法调用信息
console.log(`Calling ${propertyKey} with`, args);
return originalMethod.apply(this, args); // 调用原始方法
};
}
class MyClass {
@logMethod // 应用方法装饰器
method(arg: string) {
console.log(`Hello, ${arg}!`); // 原始方法逻辑
}
}
const myClass = new MyClass();
myClass.method("world");
// 输出:
// Calling method with ["world"]
// Hello, world!访问器装饰器
typescript
// 访问器装饰器示例
function readonly(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.writable = false; // 设置属性为只读
}
class MyClass {
@readonly // 应用访问器装饰器
prop: string = "Hello, world!"; // 定义只读属性
}
const myClass = new MyClass();
myClass.prop = "Goodbye, world!"; // 尝试修改只读属性会抛出错误
// 输出:
// TypeError: Cannot assign to read only property 'prop' of object '#<MyClass>'属性装饰器
typescript
// 属性装饰器示例
function enumerable(value: boolean) {
return function (target: any, propertyKey: string) {
const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey) || {};
descriptor.enumerable = value; // 设置属性是否可枚举
Object.defineProperty(target, propertyKey, descriptor); // 更新属性描述符
};
}
class MyClass {
@enumerable(false) // 应用属性装饰器
prop: string = "Hello, world!";
}
const myClass = new MyClass();
for (const key in myClass) {
console.log(key); // 只有可枚举的属性会被输出
}
// 输出:
// prop参数装饰器
typescript
// 参数装饰器示例
function minArgs(count: number) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 检查参数数量
if (args.length < count) {
throw new Error(`Expected at least ${count} arguments.`);
}
return originalMethod.apply(this, args);
};
};
}
class MyClass {
@minArgs(2) // 应用参数装饰器
method(arg1: string, arg2: string) {
console.log(`Hello, ${arg1} and ${arg2}!`); // 方法逻辑
}
}
const myClass = new MyClass();
myClass.method("world"); // 参数不足会抛出错误
// 输出:
// Error: Expected at least 2 arguments.装饰器工厂
typescript
// 装饰器工厂示例
function log(prefix: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 输出带前缀的日志信息
console.log(`${prefix} ${propertyKey} with`, args);
return originalMethod.apply(this, args);
};
};
}
class MyClass {
@log("Before") // 应用装饰器工厂
method(arg: string) {
console.log(`Hello, ${arg}!`); // 方法逻辑
}
@log("After") // 应用装饰器工厂
method2(arg: string) {
console.log(`Goodbye, ${arg}!`); // 方法逻辑
}
}
const myClass = new MyClass();
myClass.method("world");
myClass.method2("world");
// 输出:
// Before method with ["world"]
// Hello, world!
// After method2 with ["world"]
// Goodbye, world!装饰器组合
typescript
// 多个装饰器组合示例
function readonly(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.writable = false; // 设置属性为只读
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string) {
const descriptor = Object.getOwnPropertyDescriptor(target, propertyKey) || {};
descriptor.enumerable = value; // 设置属性是否可枚举
Object.defineProperty(target, propertyKey, descriptor); // 更新属性描述符
};
}
function minArgs(count: number) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 检查参数数量
if (args.length < count) {
throw new Error(`Expected at least ${count} arguments.`);
}
return originalMethod.apply(this, args);
};
};
}
function log(prefix: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
// 输出带前缀的日志信息
console.log(`${prefix} ${propertyKey} with`, args);
return originalMethod.apply(this, args);
};
};
}
class MyClass {
@log("Before") // 日志装饰器
@minArgs(2) // 参数检查装饰器
@enumerable(false) // 属性可枚举性装饰器
method(arg1: string, arg2: string) {
console.log(`Hello, ${arg1} and ${arg2}!`); // 方法逻辑
}
@log("After") // 日志装饰器
method2(arg: string) {
console.log(`Goodbye, ${arg}!`); // 方法逻辑
}
}
const myClass = new MyClass();
myClass.method("world", "universe");
myClass.method2("world");
// 输出:
// Before method with ["world", "universe"]
// Hello, world and universe!
// After method2 with ["world"]
// Goodbye, world!