面试题答案
一键面试结合原理
- TypeScript方法装饰器:
- 方法装饰器是在类的方法定义前添加的装饰器,它可以用来修改类方法的行为。语法为
@装饰器名
。例如,在类MyClass
的方法myMethod
上使用装饰器:
class MyClass { @myDecorator myMethod() { // 方法逻辑 } }
- 装饰器函数接收三个参数:
target
(对于方法装饰器,是类的原型对象),propertyKey
(方法名),descriptor
(包含方法属性的对象,如value
、writable
等)。通过修改descriptor
,可以改变方法的行为,比如添加额外的逻辑、修改返回值等。
- 方法装饰器是在类的方法定义前添加的装饰器,它可以用来修改类方法的行为。语法为
- 依赖注入框架(以InversifyJS为例):
- InversifyJS使用容器(
Container
)来管理对象的创建和依赖关系。通过将类绑定到容器中,可以指定如何创建实例以及其依赖项。例如:
import { Container } from 'inversify'; class MyService {} const container = new Container(); container.bind<MyService>('MyService').to(MyService);
- 当需要获取一个对象实例时,可以从容器中解析它,容器会自动处理其依赖项的创建和注入。
- InversifyJS使用容器(
- 结合原理:
- 利用TypeScript方法装饰器,可以在方法调用时,从依赖注入框架的容器中获取所需的依赖项并注入到方法中。例如,定义一个装饰器
injectService
,在方法调用前从InversifyJS容器中获取指定服务并作为参数注入到方法中。
- 利用TypeScript方法装饰器,可以在方法调用时,从依赖注入框架的容器中获取所需的依赖项并注入到方法中。例如,定义一个装饰器
优势
- 灵活性:
- 可以在不改变类的构造函数的情况下,灵活地为方法注入依赖。这对于在大型项目中修改现有类的依赖关系非常方便,避免了在构造函数中传递大量依赖带来的复杂性。
- 不同的方法可以根据自身需求注入不同的依赖,而不需要在类级别统一管理所有依赖。
- 可维护性:
- 依赖关系在装饰器中明确表示,使得代码结构更加清晰,易于理解和维护。例如,通过查看方法上的装饰器,就能清楚知道该方法依赖哪些服务。
- 当依赖关系发生变化时,只需要修改装饰器的逻辑,而不需要在整个类的代码中查找和修改依赖的使用。
- 代码复用:
- 可以将通用的依赖注入逻辑封装在装饰器中,供多个类的方法复用。例如,定义一个用于注入数据库连接服务的装饰器,可以在多个需要数据库操作的方法中使用。
应用场景
- 业务逻辑层方法依赖注入:
- 在业务逻辑类中,不同的业务方法可能依赖不同的服务,如用户服务、订单服务等。通过方法装饰器,可以为每个方法按需注入所需的服务。
- 例如,在一个电商系统中,订单处理类
OrderProcessor
的processOrder
方法可能依赖库存服务InventoryService
和支付服务PaymentService
。
- 控制器方法依赖注入:
- 在Web应用的控制器中,不同的HTTP请求处理方法可能依赖不同的服务。例如,一个用户管理控制器
UserController
的getUser
方法可能依赖用户服务UserService
,而createUser
方法除了依赖UserService
,还可能依赖邮件服务EmailService
来发送注册通知。
- 在Web应用的控制器中,不同的HTTP请求处理方法可能依赖不同的服务。例如,一个用户管理控制器
示例代码
- 安装依赖:
- 首先安装InversifyJS和reflect - metadata(InversifyJS需要它来支持装饰器元数据):
npm install inversify reflect - metadata --save
- 在
tsconfig.json
中启用装饰器相关配置:
{ "experimentalDecorators": true, "emitDecoratorMetadata": true }
- 定义服务和装饰器:
import { Container } from 'inversify'; import 'reflect - metadata'; // 定义服务 class UserService { getUser() { return 'User data'; } } // 定义方法装饰器 function injectService<T>(serviceIdentifier: symbol) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { const container = new Container(); container.bind<T>(serviceIdentifier).to(UserService); const service = container.get<T>(serviceIdentifier); return originalMethod.apply(this, [service, ...args]); }; return descriptor; }; } const USER_SERVICE_IDENTIFIER = Symbol('UserService'); // 使用装饰器的类 class UserController { @injectService(USER_SERVICE_IDENTIFIER) getUser(service: UserService) { return service.getUser(); } } const controller = new UserController(); console.log(controller.getUser());
- 在上述代码中,定义了
UserService
服务,injectService
装饰器用于在方法调用时从容器中获取指定服务并注入。UserController
类的getUser
方法使用了该装饰器,在调用getUser
方法时,会自动注入UserService
实例并调用其getUser
方法。实际项目中,可以将容器管理等逻辑进行更合理的封装和优化,如使用单例模式管理容器,以提高性能和可维护性。
- 在上述代码中,定义了