setInterval返回值作用域异常:类中intervalId始终为undefined
问题根源:this指向丢失
你遇到的核心问题是类方法作为setInterval回调时,this的指向发生了偏移。当signalTriggered被setInterval调用时,它的this不再指向Signal类的实例,而是指向全局执行上下文(浏览器环境是window,Node.js环境是global),自然访问不到实例上的intervallId属性,所以打印出来是undefined。
另外你注释里说console.log("Never executed.")和console.log("Done.")没执行,这是误解——setInterval是异步任务,主线程会先执行完所有同步代码,所以这两个日志会立刻打印,2秒后才会触发signalTriggered里的逻辑。
三种修复方案
方案1:用箭头函数包裹回调
箭头函数不会创建自己的this,会继承外层函数(这里是wait方法)的this指向,也就是Signal实例:
class Signal { t: number; private intervallId: number | undefined; constructor(t: number) { this.t = t; } wait() { // 用箭头函数包裹回调,绑定实例this this.intervallId = setInterval(() => this.signalTriggered(), this.t); console.log("会被执行的log"); } signalTriggered() { const triggerTime: number = Date.now(); console.log(this.intervallId); // 现在能拿到正确的定时器ID if (this.intervallId) { clearInterval(this.intervallId); console.log(triggerTime); } } } const timer = new Signal(2000); timer.wait(); console.log("Done."); // 会先于回调打印
方案2:用bind绑定this
在传递回调给setInterval时,用bind把signalTriggered的this强制绑定到当前实例:
wait() { this.intervallId = setInterval(this.signalTriggered.bind(this), this.t); console.log("会被执行的log"); }
方案3:将方法定义为箭头函数属性
直接把signalTriggered定义为类的箭头函数属性,这样它的this会永久绑定到实例:
class Signal { t: number; private intervallId: number | undefined; constructor(t: number) { this.t = t; } wait() { this.intervallId = setInterval(this.signalTriggered, this.t); console.log("会被执行的log"); } // 定义为箭头函数属性,this永久绑定实例 signalTriggered = () => { const triggerTime: number = Date.now(); console.log(this.intervallId); if (this.intervallId) { clearInterval(this.intervallId); console.log(triggerTime); } } }
额外优化建议
如果你的需求是定时器只执行一次,其实更推荐用setTimeout代替setInterval——毕竟setInterval是重复执行,你还要手动清除,而setTimeout本身就是单次执行,代码更简洁:
wait() { setTimeout(() => { console.log(Date.now()); }, this.t); }
内容的提问来源于stack exchange,提问作者Manticor
相关产品推荐
相关产品推荐

