答案:依赖注入与控制反转通过将对象创建权交由外部容器实现解耦,IoC容器核心功能包括依赖注册、解析和生命周期管理,示例实现展示了手动绑定与解析流程,并可通过构造函数参数自动注入优化,提升代码可测试性与灵活性。

依赖注入(Dependency Injection, DI)和控制反转(Inversion of Control, IoC)是现代JavaScript/TypeScript应用中解耦组件、提升可测试性和可维护性的核心技术。IoC容器是实现依赖注入的载体,它负责管理对象的生命周期和依赖关系。下面通过一个简易的IoC容器实现,讲解其核心原理。
什么是依赖注入与控制反转
在传统编程中,一个类通常会自己创建它所依赖的对象,导致高度耦合。而控制反转是指将对象的创建和管理权从类内部转移到外部容器。依赖注入是实现IoC的一种方式,即由外部将依赖“注入”到类中,而不是类自己去获取。
例如:
// 传统方式:类主动创建依赖
class UserService {
constructor() {
this.db = new Database();
}
}
// 使用依赖注入:依赖由外部传入
class UserService {
constructor(db) {
this.db = db;
}
}
IoC容器的核心功能
一个基本的IoC容器需要实现以下能力:
立即学习“Java免费学习笔记(深入)”;
- 注册依赖:将类或实例绑定到一个标识符(如字符串token或Symbol)
- 解析依赖:根据标识符创建或获取实例,自动处理其依赖项
- 生命周期管理:支持单例(Singleton)或多例(Transient)模式
简易IoC容器实现
下面是一个轻量级IoC容器的实现示例:
class Container {
constructor() {
this.bindings = new Map();
this.instances = new Map(); // 缓存单例
}
// 注册依赖
bind(token, implementation, singleton = false) {
this.bindings.set(token, { implementation, singleton });
}
// 解析并创建实例
resolve(token) {
if (this.instances.has(token)) {
return this.instances.get(token);
}
const binding = this.bindings.get(token);
if (!binding) {
throw new Error(`No binding found for ${token.toString()}`);
}
const { implementation, singleton } = binding;
const instance = new implementation();
// 如果是单例,缓存实例
if (singleton) {
this.instances.set(token, instance);
}
return instance;}
}
使用示例:
class Database {
query(sql) {
return `Executing: ${sql}`;
}
}
class UserService {
constructor(db) {
this.db = db;
}
getUser(id) {
return this.db.query(SELECT * FROM users WHERE id = ${id});
}
}
const container = new Container();
container.bind('db', Database, true); // 单例
container.bind('userService', class extends UserService {
constructor() {
super(container.resolve('db'));
}
});
const userService = container.resolve('userService');
console.log(userService.getUser(1)); // 输出: Executing: SELECT * FROM users WHERE id = 1
自动依赖注入(基于构造函数参数)
更高级的IoC容器可以自动分析构造函数参数,实现自动注入。这通常借助装饰器或反射机制(如TypeScript的emitDecoratorMetadata)。
简化版自动注入思路:
- 通过
Function.prototype.toString()解析构造函数参数名 - 映射参数名到注册的token
- 递归解析所有依赖
例如:
// 伪代码:自动解析构造函数依赖
function getDependencies(ctor) {
const args = ctor.toString().match(/constructor\s*\(\s*([^)]*)\)/);
if (!args) return [];
return args[1].split(',').map(arg => arg.trim());
}
结合此机制,容器可在resolve时自动注入所需依赖,无需手动传递。
基本上就这些。IoC容器的本质是“注册-解析”模型,通过集中管理依赖关系,让代码更灵活、易于替换和测试。实际项目中可使用InversifyJS等成熟框架,但理解底层原理有助于更好地设计应用结构。










