在 TypeScript 中,装饰器是一种特殊的语法,它可以在类、方法、属性等声明前面添加一些额外的元数据,从而影响它们的行为。属性装饰器是一种特殊的装饰器,它只能应用于类的属性上,可以用来修改属性的行为或元数据。
装饰器的基本用法
装饰器是通过 @ 符号来使用的,例如:
@decorator class MyClass { // ... }
其中 decorator 是一个函数,它会被传递给 MyClass 的构造函数作为参数。装饰器可以用来修改 MyClass 的行为,例如:
function decorator(constructor: Function) { constructor.prototype.greeting = function() { console.log('Hello, world!'); } } @decorator class MyClass { // ... } const obj = new MyClass(); obj.greeting(); // 输出 "Hello, world!"
在这个例子中,我们定义了一个装饰器函数 decorator,它会在 MyClass 的构造函数上添加一个 greeting 方法。当我们创建 MyClass 的实例时,就可以调用这个方法。
属性装饰器的基本用法
属性装饰器是一种特殊的装饰器,它只能应用于类的属性上,可以用来修改属性的行为或元数据。属性装饰器的语法如下:
class MyClass { @decorator myProperty: string; }
其中 decorator 是一个函数,它会在 myProperty 上应用。属性装饰器可以用来修改 myProperty 的行为,例如:
function decorator(target: any, propertyKey: string) { let value = target[propertyKey]; const getter = function() { console.log(`Getting value: ${value}`); return value; }; const setter = function(newValue: any) { console.log(`Setting value: ${newValue}`); value = newValue; }; Object.defineProperty(target, propertyKey, { get: getter, set: setter, enumerable: true, configurable: true }); } class MyClass { @decorator myProperty: string = 'default value'; } const obj = new MyClass(); console.log(obj.myProperty); // 输出 "Getting value: default value" 和 "default value" obj.myProperty = 'new value'; // 输出 "Setting value: new value" console.log(obj.myProperty); // 输出 "Getting value: new value" 和 "new value"
在这个例子中,我们定义了一个属性装饰器函数 decorator,它会在 MyClass 的 myProperty 属性上添加 getter 和 setter 方法。当我们读取或设置这个属性时,就会触发这些方法。
装饰器的应用场景
装饰器可以用来实现许多有用的功能,例如:
1. 日志记录
我们可以使用装饰器来记录函数的调用和返回值,例如:
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Calling method ${propertyKey} with arguments:`, args); const result = originalMethod.apply(this, args); console.log(`Method ${propertyKey} returned:`, result); return result; }; return descriptor; } class MyClass { @log myMethod(param1: string, param2: number): boolean { return true; } } const obj = new MyClass(); obj.myMethod('test', 123); // 输出 "Calling method myMethod with arguments:","Method myMethod returned:" 和 true
在这个例子中,我们定义了一个装饰器函数 log,它会在 MyClass 的 myMethod 方法上添加日志记录功能。当我们调用这个方法时,就会输出日志信息。
2. 权限控制
我们可以使用装饰器来实现权限控制,例如:
function checkPermission(permission: string) { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function(...args: any[]) { if (hasPermission(permission)) { return originalMethod.apply(this, args); } else { throw new Error(`Permission denied: ${permission}`); } }; return descriptor; } } class MyClass { @checkPermission('read') myMethod(): void { console.log('Method executed'); } } const obj = new MyClass(); obj.myMethod(); // 输出 "Method executed"
在这个例子中,我们定义了一个装饰器函数 checkPermission,它会在 MyClass 的 myMethod 方法上添加权限控制功能。当我们调用这个方法时,就会检查当前用户是否有 read 权限,如果有,则执行原始方法,否则抛出异常。
3. 缓存数据
我们可以使用装饰器来实现数据缓存,例如:
function memoize(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; const cache = new Map(); descriptor.value = function(...args: any[]) { const key = args.join('|'); if (cache.has(key)) { console.log(`Using cached result for ${key}`); return cache.get(key); } else { console.log(`Calculating result for ${key}`); const result = originalMethod.apply(this, args); cache.set(key, result); return result; } }; return descriptor; } class MyClass { @memoize myMethod(param1: string, param2: number): boolean { return true; } } const obj = new MyClass(); console.log(obj.myMethod('test', 123)); // 输出 "Calculating result for test|123" 和 true console.log(obj.myMethod('test', 123)); // 输出 "Using cached result for test|123" 和 true
在这个例子中,我们定义了一个装饰器函数 memoize,它会在 MyClass 的 myMethod 方法上添加数据缓存功能。当我们调用这个方法时,就会检查是否已经计算过相同的参数,如果是,则使用缓存中的结果,否则计算结果并将其存储到缓存中。
总结
装饰器是 TypeScript 中的一种特殊语法,它可以在类、方法、属性等声明前面添加一些额外的元数据,从而影响它们的行为。属性装饰器是一种特殊的装饰器,它只能应用于类的属性上,可以用来修改属性的行为或元数据。装饰器可以用来实现许多有用的功能,例如日志记录、权限控制、数据缓存等。在使用装饰器时,我们需要注意它们的执行顺序,以及它们可能会对性能产生影响。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65c0102badd4f0e0ff9c217e