You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

TypeScript中重置单例实例的正确方式

TypeScript中重置单例实例的正确方式

咱们先把你的几个疑问逐个掰明白,再给出调整后的完整代码方案,确保你的单例重置逻辑既安全又规范。

首先先提个小细节:你原来的类定义有个语法错误,export class MyTracker = { ... } 应该改成 export class MyTracker { ... },这个先修正过来。

你的疑问解答&方案调整

1. reset() 方法应该是静态的吗?

必须做成静态方法
单例的核心是类的静态属性instance,重置它的操作属于类本身的行为,而不是某个具体实例的行为。如果做成实例方法,你得先通过getInstance()拿到实例才能调用reset(),但如果instance已经是null了,你根本调用不了。做成静态方法后,直接通过MyTracker.reset()就能触发重置,不管当前有没有实例都能正常工作。

2. 要不要检查MyTracker.instance存在再执行重置逻辑?

一定要加检查
如果当前instance已经是null,你再去访问它的属性(比如instance.onVisibilityChange)或者执行实例相关的清理操作,直接会抛出空指针错误。所以先把实例存到临时变量里,判断存在后再执行后续逻辑,避免不必要的报错。

3. 移除事件监听时用this.onVisibilityChange还是MyTracker.instance.onVisibilityChange

这里有个容易踩的坑:事件监听的添加和移除必须用完全相同的函数引用
首先你得先在构造函数里把onVisibilityChangethis绑定到实例,不然在addEventListener里,this会默认指向document,导致后续移除监听时引用不匹配(直接移除失败)。然后在静态的reset()方法里,this指向的是类本身,不是实例,所以必须用MyTracker.instance?.onVisibilityChange(也就是实例上绑定后的函数引用)来移除监听。

4. 要不要重置myTrackingMetrics?设为null后会自动清理吗?

如果把instance设为null,并且没有其他地方引用这个旧实例,JS的垃圾回收机制会自动回收整个实例对象,包括它的myTrackingMetrics数组,所以不需要特意去重置它。不过如果担心旧的metrics被其他意外引用(比如外部变量缓存了这个数组),手动清空instance.myTrackingMetrics = []也没问题,但这不是必须操作。

调整后的完整代码

export class MyTracker {
  private static instance: MyTracker | null = null;
  private myTrackingMetrics: string[] = [];

  private constructor() {
    // 绑定this,确保onVisibilityChange的引用始终一致
    this.onVisibilityChange = this.onVisibilityChange.bind(this);
    this.initMetrics();
  }

  private initMetrics() {
    document.addEventListener('visibilitychange', this.onVisibilityChange);
    this.myTrackingMetrics.push("dummy metric");
  }

  private onVisibilityChange() {
    console.log("foo");
  }

  public static getInstance(): MyTracker {
    if (!MyTracker.instance) {
      MyTracker.instance = new MyTracker();
    }
    return MyTracker.instance;
  }

  public static reset() {
    const currentInstance = MyTracker.instance;
    if (!currentInstance) return;

    // 移除事件监听,必须用和添加时一致的引用
    document.removeEventListener('visibilitychange', currentInstance.onVisibilityChange);
    // 可选:手动清空metrics(非必须,实例回收后会自动清理)
    currentInstance.myTrackingMetrics = [];
    // 重置单例实例
    MyTracker.instance = null;
  }
}

额外提醒

调用reset()后,下次调用getInstance()会重新创建一个新的实例,自动执行构造函数里的初始化逻辑,包括重新绑定事件监听,完全符合预期。

内容来源于stack exchange

火山引擎 最新活动