javascript 的 class 可封装轻量级 di 容器,核心是用 map 管理 token 与工厂/实例映射,支持单例、瞬态生命周期;typescript 环境借助装饰器和 reflect 元数据实现自动构造函数注入,javascript 环境需手动传入 token 数组或显式注册依赖。

JavaScript 的 class 语法本身不提供依赖注入(DI)容器功能,但你可以用 class 封装一个轻量级 DI 容器,核心是管理依赖的注册、解析和生命周期。关键不是“用 class 实现 DI”,而是用 class 构建一个可复用、可配置的容器实例。
定义容器类:支持注册与解析
创建一个 Container 类,内部用 Map 存储服务标识(token)与工厂函数或实例的映射。支持单例(singleton)、瞬态(transient)等基本生命周期:
- 注册时传入 token(字符串或 Symbol)和工厂函数,避免硬编码类名,提升可测试性
-
解析时递归处理构造函数参数,通过
Reflect.getMetadata('design:paramtypes', target)获取类型元数据(需配合tsconfig.json中"emitDecoratorMetadata": true和"experimentalDecorators": true) - 缓存单例实例,首次解析后保存,后续直接返回
支持构造函数自动注入(TypeScript 环境)
利用 TypeScript 的装饰器 + 元数据反射能力,在类定义阶段标记依赖。例如:
@Injectable()
class UserService {
constructor(private db: DatabaseService) {}
}
@Injectable()
class DatabaseService {}
// Container 自动识别 UserService 构造函数需要 DatabaseService,
// 并递归解析其依赖树
注意:纯 JavaScript 环境无法获取参数类型,需手动传入 token 数组(如 container.register('UserService', [DatabaseService], (...deps) => new UserService(...deps)))。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
手动注册与显式解析更可控
跳过反射,用显式 token 明确依赖关系,适合 JS 项目或复杂场景:
- 用
Symbol('UserService')或字符串'user-service'作唯一 token - 注册时绑定 factory 函数,例如:
container.register(USER_SERVICE, () => new UserService(container.get(DB_SERVICE))) - 解析时按需调用
container.get(USER_SERVICE),无隐式行为,调试友好
避免常见陷阱
DI 容器易出错的地方:
- 循环依赖:注册前先检查依赖图,或延迟解析(用 getter / factory 包裹)
- 作用域混淆:区分全局单例、请求作用域(如 Express 中每个 request 新建子容器)
- 未注册 token 报错不清晰:get 时抛出含 token 名和调用栈的错误,方便定位
-
类未声明默认导出或命名冲突:推荐用 Symbol 或字符串 token,而非依赖
constructor.name
不复杂但容易忽略细节。核心是把“谁创建谁”、“谁依赖谁”从代码里抽出来,由容器统一协调。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










