Skip to content

支持 javascript 项目

在 TypeScript 项目中,可以直接使用装饰器语法(@Inject@PostConstruct 等)来声明依赖。 但在纯 JavaScript 项目中,由于没有装饰器语法支持,本库提供了 decorate 辅助函数来手动应用装饰器。

decorate 函数签名

ts
function decorate(decorator: any, target: any, key: string): void
  • decorator:单个装饰器或装饰器数组
  • 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 行为。

参考资料

点击这里查看装饰器的编译结果