依赖注入与控制反转通过将对象创建交由外部容器管理,降低代码耦合。在TypeScript中,利用装饰器和reflect-metadata可实现IoC容器,通过@Injectable标记可注入类,结合Map存储依赖映射,递归解析构造函数参数类型完成自动注入,支持复杂应用的解耦与维护。

依赖注入(Dependency Injection, DI)和控制反转(Inversion of Control, IoC)是现代前端开发中提升代码可维护性与解耦的关键设计模式。在JavaScript尤其是TypeScript生态中,借助装饰器(Decorator)语法可以优雅地实现IoC容器,让对象的创建和依赖管理自动化。
什么是IoC容器与依赖注入
控制反转是指将对象的创建和生命周期管理从代码内部转移到外部容器。原本由类自己实例化依赖,现在由外部“注入”进来,从而降低耦合度。
依赖注入是实现IoC的一种方式,常见形式有构造函数注入、属性注入和方法注入。在JavaScript中,我们可以通过一个IoC容器来管理所有服务的注册与解析。
举个简单例子:如果一个UserService需要UserRepository,传统做法是在UserService内部new UserRepository(),但这样就绑死了实现。使用DI后,UserRepository由容器传入,UserService无需关心如何创建它。
立即学习“Java免费学习笔记(深入)”;
使用装饰器声明可注入服务
TypeScript支持装饰器语法(需开启experimentalDecorators和emitDecoratorMetadata),我们可以用@Injectable装饰器标记哪些类可以被IoC容器管理。
示例:
function Injectable(): ClassDecorator { return target => { // 标记该类可被注入,可附加元数据 };}@Injectable()class UserRepository { findAll() { return ['user1', 'user2']; }}@Injectable()class UserService { constructor(private repo: UserRepository) {} listUsers() { return this.repo.findAll(); }}
通过装饰器,我们为类添加了元信息,IoC容器可以根据这些信息自动解析依赖关系。
实现简易IoC容器
一个基本的IoC容器需要具备注册(register)和获取(resolve)功能。它维护一个依赖映射表,并能递归解析构造函数参数。
Kive
一站式AI图像生成和管理平台
171 查看详情
核心思路:
使用Map保存token到类的映射 利用reflect-metadata读取构造函数参数类型 递归创建实例并注入依赖
实现代码:
import 'reflect-metadata';const DESIGN_PARAM_TYPES = 'design:paramtypes';const container = new Map();function register(token: any, useClass: any) { container.set(token, useClass);}function resolve(token: any): T { const clazz = container.get(token); if (!clazz) throw new Error(`No provider for ${token.name}`); const paramTypes = Reflect.getMetadata(DESIGN_PARAM_TYPES, clazz) || []; const dependencies = paramTypes.map((dep: any) => resolve(dep)); return new clazz(...dependencies);}
注册服务:
register(UserRepository, UserRepository);register(UserService, UserService);const userService = resolve(UserService);console.log(userService.listUsers()); // ['user1', 'user2']
结合装饰器自动注入构造参数
上述resolve方法依赖reflect-metadata获取构造函数参数类型。只要开启了emitDecoratorMetadata,TypeScript会在编译时自动写入参数类型元数据,IoC容器就能“知道”某个类需要哪些依赖。
注意:基础类型(如string、number)不会被保留,只有引用类型(class)会被记录。因此依赖项必须是类或明确的token。
为了更清晰地控制注入,也可以使用@Inject装饰器指定token:
function Inject(token: any): ParameterDecorator { return (target, propertyKey, parameterIndex) => { const existingInjectedTokens = Reflect.getOwnMetadata('injectedParams', target) || []; existingInjectedTokens[parameterIndex] = token; Reflect.defineMetadata('injectedParams', existingInjectedTokens, target); };}
这样即使类型信息缺失,也能手动指定注入内容。
基本上就这些。通过装饰器 + reflect-metadata + 容器管理,JavaScript也能实现类似Angular的依赖注入机制。虽然原生JS不内置DI,但在复杂应用或框架开发中,这样的模式非常实用。
以上就是JavaScript依赖注入_IoC容器与装饰器实现的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/863606.html
微信扫一扫
支付宝扫一扫