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

对象方法内使用setTimeout导致代码无法终止的问题

为啥你的setTimeout递归停不下来?

先把你的代码贴出来方便咱们分析:

var myObj = { 
  myFunc: function () { 
    var self = this; 
    var timer = setTimeout(function () { 
      console.log('Timeout called'); 
      self.myFunc(); 
    }, 100); 
  } 
}; 
myObj.myFunc(); 
myObj = null;

核心问题:闭包攥着原对象的引用没放

你以为把myObj = null就能让对象被垃圾回收,但实际上**self变量在setTimeout的回调闭包里,还死死引用着最初的myObj对象**。当你第一次调用myObj.myFunc()时,this指向的是原对象,self把这个引用存了下来——哪怕外部的myObj变量被设为null,闭包里的self还抓着原对象不放,所以它不会被销毁,self.myFunc()会一直递归调用,定时器自然停不下来。

两种实用修复方案

你需要主动给递归加个“刹车”,这里给你两种常用的思路:

方案1:加个停止标志

给对象加一个状态变量,每次调用myFunc前先检查这个标志:

var myObj = { 
  isStopped: false,
  myFunc: function () { 
    if (this.isStopped) return; // 触发停止就直接返回
    var self = this; 
    var timer = setTimeout(function () { 
      console.log('Timeout called'); 
      self.myFunc(); 
    }, 100); 
  } 
}; 
myObj.myFunc(); 
// 比如500毫秒后停止
setTimeout(() => {
  myObj.isStopped = true;
}, 500);

方案2:保存定时器ID,手动清除

把定时器ID存在对象里,专门写个方法来清除定时器:

var myObj = { 
  timerId: null,
  myFunc: function () { 
    var self = this; 
    this.timerId = setTimeout(function () { 
      console.log('Timeout called'); 
      self.myFunc(); 
    }, 100); 
  },
  stop: function() {
    clearTimeout(this.timerId); // 清除当前的定时器
  }
}; 
myObj.myFunc(); 
// 500毫秒后停止并释放对象
setTimeout(() => {
  myObj.stop();
  myObj = null; // 现在对象可以被正常回收了
}, 500);

小提醒

闭包是个好用的特性,但偶尔也会“帮倒忙”——比如意外保留引用导致内存泄漏或者无限递归。记住:只要闭包里还拿着对象的引用,哪怕外部变量被重新赋值,原对象也不会被垃圾回收哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:26:35