JavaScript/TypeScript 中的模块导出方式

205 阅读1分钟

两种常见的导出方式

1. 类导出

// 传统类导出
export class MyService {
  constructor() {}
  doSomething() {}
}

// 使用时需要实例化
import { MyService } from './my-service';
const service = new MyService();

2. 实例导出

// 直接导出实例
class MyService {
  constructor() {}
  doSomething() {}
}
export default new MyService();

// 使用时直接使用实例
import myService from './my-service';
myService.doSomething();

各自的应用场景

类导出适用于:

  1. 需要多个实例的场景
  2. 需要通过构造函数传参的场景
  3. 实例需要独立的状态管理
  4. 测试时需要 mock 不同实例

实例导出适用于:

  1. 全局共享状态的场景
  2. 工具类服务
  3. 配置管理服务
  4. 需要确保单例的场景

实现原理

类导出的实现:

// service.ts
export class Service {
  private state = {};
  
  constructor(config) {
    this.init(config);
  }
}

// usage.ts
import { Service } from './service';
const serviceA = new Service(configA);
const serviceB = new Service(configB);

实例导出的实现:

// service.ts
class Service {
  private static instance: Service;
  private constructor() {}
  
  public static getInstance() {
    if (!Service.instance) {
      Service.instance = new Service();
    }
    return Service.instance;
  }
}
export default Service.getInstance();

// 或者更简单的方式
class Service {}
export default new Service();

性能考虑

  1. 内存占用
  • 类导出:每个实例都占用独立内存
  • 实例导出:全局共享一份内存
  1. 初始化时机
  • 类导出:使用时才初始化
  • 实例导出:模块加载时就初始化

最佳实践

  1. 工具类服务:使用实例导出
// date-formatter.ts
class DateFormatter {
  format() {}
}
export default new DateFormatter();
  1. 业务服务:使用类导出
// user-service.ts
export class UserService {
  constructor(userId: string) {}
  getProfile() {}
}

总结

选择哪种导出方式应该基于:

  1. 是否需要多实例
  2. 是否需要共享状态
  3. 初始化时机的要求
  4. 测试的便利性
  5. 内存使用的考虑

合理选择导出方式可以让代码更加清晰、易维护,同时避免不必要的性能开销。