在 TypeScript 中,装饰器是一种特殊的语法,它可以用于为类、方法、属性等添加额外的元数据信息,从而实现一些高级的功能。本文将介绍 TypeScript 中装饰器的基本使用方法,并结合实例深入探讨其应用实践。
基本语法
在 TypeScript 中,装饰器的语法格式为 @decorator
,其中 decorator
可以是任意一个函数。装饰器函数的参数分别为被装饰的类、方法、属性等的构造函数或原型,具体使用方法如下:
// javascriptcn.com 代码示例 // 类装饰器 function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) { return class extends constructor { newProperty = 'new property'; hello = 'override'; }; } @classDecorator class Greeter { property = 'property'; hello: string; constructor(m: string) { this.hello = m; } } console.log(new Greeter('world')); // { property: 'property', hello: 'override', newProperty: 'new property' }
上面的代码中,classDecorator
是一个类装饰器,它接受一个构造函数作为参数,并返回一个新的构造函数。在 @classDecorator
装饰器应用到 Greeter
类上时,它会将原来的构造函数替换为新的构造函数,从而实现对类的修改。
除了类装饰器,还有方法装饰器、属性装饰器等其他类型的装饰器,它们的使用方法与类装饰器类似,只是作用的对象不同。下面我们将结合具体实例来介绍这些装饰器的应用实践。
实例分析
方法装饰器
方法装饰器用于修改类中的方法,常见的用途包括添加日志、权限控制、性能分析等。下面是一个简单的示例,它使用方法装饰器为一个类中的方法添加日志输出功能:
// javascriptcn.com 代码示例 function log(target: any, name: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`[${new Date().toISOString()}] Call: ${name}(${args})`); return originalMethod.apply(this, args); }; return descriptor; } class MyClass { @log myMethod(arg: string) { console.log(`Hello, ${arg}!`); } } const myObj = new MyClass(); myObj.myMethod('world');
在上面的代码中,log
方法装饰器接受三个参数:target
表示被装饰的类的原型,name
表示被装饰的方法的名称,descriptor
表示被装饰的方法的属性描述符。在装饰器函数中,我们首先保存原始的方法实现,然后将方法实现替换为一个新的方法,这个新的方法会在原始方法执行前输出日志,然后调用原始方法,并返回原始方法的返回值。
在上面的示例中,我们为 MyClass
类中的 myMethod
方法应用了 @log
装饰器,这个装饰器会将方法的调用信息输出到控制台中。当我们创建 MyClass
的实例并调用 myMethod
方法时,就会看到类似下面的输出:
[2022-01-01T00:00:00.000Z] Call: myMethod(world) Hello, world!
类装饰器
类装饰器用于修改类本身,常见的用途包括添加元数据信息、注册到某个容器中、修改类的行为等。下面是一个示例,它使用类装饰器为一个类添加元数据信息:
// javascriptcn.com 代码示例 const METADATA_KEY = Symbol('metadata'); function metadata(key: string, value: any) { return function (target: any) { target[METADATA_KEY] = target[METADATA_KEY] || {}; target[METADATA_KEY][key] = value; }; } @metadata('author', 'John Doe') @metadata('version', '1.0.0') class MyClass {} console.log(MyClass[METADATA_KEY]); // { author: 'John Doe', version: '1.0.0' }
在上面的代码中,metadata
类装饰器接受两个参数:key
表示元数据的键,value
表示元数据的值。在装饰器函数中,我们通过修改类的原型对象来添加元数据信息。
在上面的示例中,我们为 MyClass
类应用了两个 @metadata
装饰器,它们分别添加了 author
和 version
两个元数据信息。当我们输出 MyClass
的 METADATA_KEY
属性时,就会看到类似下面的输出:
{ author: 'John Doe', version: '1.0.0' }
属性装饰器
属性装饰器用于修改类中的属性,常见的用途包括为属性添加校验、缓存、计算等功能。下面是一个示例,它使用属性装饰器为一个类中的属性添加缓存功能:
// javascriptcn.com 代码示例 function cache(target: any, name: string) { const value = target[name]; const cacheName = `_${name}`; Object.defineProperty(target, name, { get() { if (!this[cacheName]) { this[cacheName] = value.call(this); } return this[cacheName]; }, set(newValue) { this[cacheName] = newValue; }, }); } class MyClass { @cache get myProperty() { console.log('get myProperty'); return Math.random(); } } const myObj = new MyClass(); console.log(myObj.myProperty); console.log(myObj.myProperty);
在上面的代码中,cache
属性装饰器接受两个参数:target
表示被装饰的类的原型,name
表示被装饰的属性的名称。在装饰器函数中,我们首先保存属性的原始值,然后定义一个新的属性描述符,这个描述符包含了一个 get
方法和一个 set
方法,用于实现属性的缓存功能。
在上面的示例中,我们为 MyClass
类中的 myProperty
属性应用了 @cache
装饰器,这个装饰器会将属性的值缓存起来,并在后续访问时直接返回缓存的值。当我们创建 MyClass
的实例并访问 myProperty
属性时,就会看到类似下面的输出:
get myProperty 0.123456789 0.123456789
总结
在 TypeScript 中,装饰器是一种非常强大的语法,它可以用于实现许多高级的功能,如日志输出、元数据添加、权限控制、性能分析、缓存等。本文介绍了 TypeScript 中装饰器的基本语法和常见用法,并结合实例深入探讨了其应用实践。通过学习本文,读者可以更好地理解 TypeScript 中装饰器的作用,掌握其使用方法,并在实际开发中灵活应用。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6565d840d2f5e1655df0b4ce