支持 javascript 项目
在 TypeScript 项目中,可以直接使用装饰器语法(@Inject、@PostConstruct 等)来声明依赖。 但在纯 JavaScript 项目中,由于没有装饰器语法支持,本库提供了 decorate 辅助函数来手动应用装饰器。
decorate 函数签名
ts
function decorate(decorator: any, target: any, key: string): voiddecorator:单个装饰器或装饰器数组target:目标类(构造函数)key:属性名或方法名(字符串类型)
decorate 函数工作原理
decorate 函数内部基于 Stage 3 装饰器规范实现,根据 key 对应的成员类型,构造符合 Stage 3 规范的 context 对象:
- 对于实例属性:构造
{ kind: 'field', name: key, ... }形式的 context 对象 - 对于实例方法:构造
{ kind: 'method', name: key, ... }形式的 context 对象
然后按逆序执行传入的装饰器数组,并通过创建 fakeInstance 来触发所有 addInitializer 回调,将元数据写入 CacheMap,供容器在解析依赖时读取。
支持范围
decorate 只支持实例属性和实例方法,不支持构造函数参数。
这是因为本库基于 Stage 3 装饰器规范,而 Stage 3 规范不支持参数装饰器。所有依赖声明统一通过实例属性装饰器(@Inject)完成。
完整使用示例
js
// 在 JavaScript 项目中使用 @kaokei/di
const { Container, Inject, PostConstruct, decorate } = require('@kaokei/di');
class LoggerService {
log(msg) {
console.log(msg);
}
}
class CountService {
constructor() {
this.count = 0;
}
}
// 手动应用装饰器,相当于在 CountService 的 logger 属性上使用 @Inject(LoggerService)
decorate(Inject(LoggerService), CountService, 'logger');
const container = new Container();
container.bind(LoggerService).toSelf();
container.bind(CountService).toSelf();
const countService = container.get(CountService);
countService.logger.log('Hello from JavaScript!');上面的 decorate(Inject(LoggerService), CountService, 'logger') 等价于在 TypeScript 中这样写:
ts
@Injectable()
class CountService {
@Inject(LoggerService)
public logger: LoggerService;
}注意:使用
decorate()的类不需要手动添加@Injectable,因为decorate()内部已模拟@Injectable行为。