详解JS中定时器setInterval和setTimeout的this指向问题

作者:半夏

时间:2026-10-21

浏览:100

本文深入解析JavaScript中setTimeout和setInterval定时器内this指向window的问题,通过示例展示原因,并提供利用闭包变量和bind()方法两种常用方案来正确绑定this,确保定时器内代码能访问当前对象属性。

文章目录

前言

定时器this指向原理

JavaScript作为单线程语言,提供了setTimeout()和setInterval()两种机制来安排代码在特定时刻执行。前者用于在指定延迟后执行一次代码,后者则用于每隔固定间隔重复执行代码,两者的使用方式相似。

在近期的开发实践中,使用定时器时发现传入的回调函数内部的this关键字默认指向window对象。下文将通过具体示例详细阐述这一现象及其原理。

参考以下示例代码:


var num = 0;
function Obj (){
 this.num = 1,
 this.getNum = function(){
 console.log(this.num);
 },
 this.getNumLater = function(){
 setTimeout(function(){
  console.log(this.num);
 }, 1000)
 }
}
var obj = new Obj; 
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//0  打印的为window.num,值为0

上述示例表明,在setTimeout回调函数中,this指向window对象。这是因为setTimeout()执行的代码处于与定义函数完全不同的执行环境中,导致其中的this关键字指向全局window对象。更多细节可查阅MDN关于setTimeout的文档。

然而,当传递给setTimeout的不是函数而是直接表达式时,this则指向当前调用对象,示例如下:


var num = 0;
function Obj (){
 this.num = 1,
 this.getNum = function(){
 console.log(this.num);
 },
 this.getNumLater = function(){
 setTimeout(console.log(this.num), 1000)
 }
}
var obj = new Obj; 
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//1  打印的为obj.num,值为1

对比上述两个例子可知,只有当setTimeout接收的参数是函数时,该函数内部的this才会指向window对象。

修正this指向的方法

若需在setTimeout中让this指向正确的对象,可采用以下两种常用方法:

第一种方法是将当前对象的this引用保存到一个变量中,然后在定时器回调函数中通过闭包访问该变量。

具体实现如下:


var num = 0;
function Obj (){
 var that = this; //将this存为一个变量,此时的this指向obj
 this.num = 1,
 this.getNum = function(){
 console.log(this.num);
 },
 this.getNumLater = function(){
 setTimeout(function(){
  console.log(that.num); //利用闭包访问that,that是一个指向obj的指针
 }, 1000)
 }
}
var obj = new Obj; 
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//1  打印的为obj.num,值为1

该方法的核心在于将当前对象的引用赋值给一个局部变量,定时器内的函数通过闭包机制访问此变量,从而获取正确的当前对象。

第二种方法是利用bind()方法。


var num = 0;
function Obj (){
 this.num = 1,
 this.getNum = function(){
 console.log(this.num);
 },
 this.getNumLater = function(){
 setTimeout(function(){
  console.log(this.num);
 }.bind(this), 1000) //利用bind()将this绑定到这个函数上
 }
}
var obj = new Obj; 
obj.getNum();//1  打印的为obj.num,值为1
obj.getNumLater()//1  打印的为obj.num,值为1

bind()是Function.prototype原型上的一个方法。当被绑定的函数执行时,bind会创建一个新的函数,并将第一个参数指定为新函数运行时的this值。在此例中,调用setTimeout时,bind创建了新函数并将当前this传入,从而确保执行结果正确。关于bind方法的详细信息可参考MDN文档。

上述两种方法均为常用且有效的解决方案。虽然也可以使用call或apply来替代bind,但call会立即执行函数,从而失去定时器的延时效果,使定时器失效。因此,推荐使用前两种方法将this正确传入setTimeout和setInterval中。

总结

以上内容涵盖了本文的全部要点,希望能为读者的学习或工作提供帮助。如有疑问,欢迎留言交流,感谢支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章