You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript秒表返回NaN及续跑功能异常问题求助

修复StopWatch的两个问题:毫秒显示NaN和暂停后继续计时

问题1:毫秒值显示NaN的原因及修复

原代码中start方法的定时器内有一行错误赋值:

this.minute, this.second, this.milliSecond = Number(this.currentWatch());
  • 逗号运算符无法完成多变量赋值,且会忽略前两个表达式,仅执行最后一步赋值
  • currentWatch()返回数组,用Number()转换数组会得到NaN,直接导致毫秒值异常
  • 另外,currentWatch()内部已将计算好的时分毫秒值赋值给实例变量,这行赋值完全多余,直接删除即可。

问题2:暂停后继续计时的实现

原代码再次启动时会重置计时起点,无法累计之前的时长。修复逻辑:

  • 停止计时时,已将累计时长存在this.duration中
  • 再次调用start时,将this.currentTime设为Date.now() - this.duration,后续计算Date.now() - this.currentTime会自动包含之前的累计时长,实现续计时
  • 将显示计时的p标签移到构造函数中创建,避免每次启动都生成新标签。

修复后的完整TypeScript代码

class StopWatch {
   private duration: number;
   private status: string;
   private currentTime: number;
   private domRef: HTMLElement | null;
   private interval: number | null;
   private milliSecond: number;
   private second: number;
   private minute: number;
   private displayEl: HTMLElement | null;

   constructor(wrapper: string) {
      this.duration = 0;
      this.milliSecond = 0;
      this.second = 0;
      this.minute = 0;
      this.interval = null;

      this.domRef = document.getElementById(wrapper);
      this.status = 'stopped';
      
      if (!this.domRef) throw new Error('Wrapper element does not exist');
      // 初始化显示元素,避免重复创建
      this.displayEl = document.createElement("p");
      this.displayEl.id = "stopwatch-display";
      document.body.appendChild(this.displayEl);
      
      this.render();
   }

   private render() {
      this.domRef!.append(
         createBtn('start', () => this.start()),
         createBtn('stop', () => this.stop()),
         createBtn('reset', () => this.reset()),
      )
   }

   private start() {
      if(this.status === 'started') throw new Error('Stopwatch already started');
      // 计算计时起点:当前时间减去已累计时长,实现续计时
      this.currentTime = Date.now() - this.duration;
      this.status = 'started';

      this.interval = setInterval(() => {
         this.currentWatch();
         this.displayEl!.innerHTML = `${this.minute} : ${this.second} : ${this.milliSecond}`;
      }, 10); // 改为10毫秒间隔,让毫秒显示更平滑
   }

   private currentWatch() {
      // 计算从起点到现在的总时长
      const elapsed = Date.now() - this.currentTime;
      this.duration = elapsed;

      if(this.status === 'stopped') this.stop();

      this.minute = Math.floor(elapsed / (1000 * 60));
      this.second = Math.floor((elapsed % (1000 * 60)) / 1000);
      this.milliSecond = Math.floor(elapsed % 1000);
   }

   stop() {
      if(this.interval) clearInterval(this.interval);
      if(this.status === 'stopped') throw new Error('Stopwatch already stopped');

      // 停止时更新累计时长
      this.duration = Date.now() - this.currentTime;
      this.status = 'stopped';

      return this.duration;
   }

   reset(){
      if(this.status === 'started') this.stop();
      this.duration = 0;
      this.minute = 0;
      this.second = 0;
      this.milliSecond = 0;
      this.displayEl!.innerHTML = `${this.minute} : ${this.second} : ${this.milliSecond}`;
   }
}

function createBtn(name: string, listener: () => void) {
   const btn = document.createElement('button');
   btn.innerText = name;
   btn.addEventListener('click', listener);
   return btn;
}

(function() {
   const btns = document.getElementsByClassName('add-btn');
   btns[0].addEventListener('click', () => {
      new StopWatch(btns[0].getAttribute('data-idw') as string);
   });
})();

额外优化点

  • 将定时器间隔从100毫秒改为10毫秒,让毫秒数更新更平滑
  • 给显示元素设置明确IDstopwatch-display,避免与其他元素冲突
  • 给interval添加number | null类型,符合TypeScript类型规范
  • 重置时同步重置时分毫秒实例变量,确保显示准确

内容的提问来源于stack exchange,提问作者arta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:20:34