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


Posted in Javascript onJanuary 06, 2017

前言

Js是一个单线程语言,可以通过setTimeout()和setInterval()来设置代码在指定时刻运行,前者是在指定时间后执行,后者是指每隔一段时间执行。两者的使用方法类似。

最近在练习写一个小例子的时候用到了定时器,发现在setInterval和setTimeout中传入函数时,函数中的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对象。

当在setTimeout中传入了一个函数,若想要让this指向正确的值,可以使用以下两种比较常用的方法来使this指向正确的值:

1.将当前对象的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

这种方法是将当前对象的引用放在一个变量里,定时器内部的函数来访问到这个变量,自然就可以得到当前的对象。

2.利用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 bind

以上两种方法都是比较常用的,当然如果使用call或apply方法来代替bind方法,得到的结果也是正确的,但是call方法会在调用之后立即执行,那样也就没有了延时的效果,定时器也就没有用了,所以推荐使用上述两种方法来将this传进setTimeout和setInterval中。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
短信提示使用 特效
Jan 19 Javascript
用javascript实现的激活输入框后隐藏初始内容
Jun 29 Javascript
JavaScript实现简单的时钟实例代码
Nov 23 Javascript
JS实现很酷的EMAIL地址添加功能实例
Feb 28 Javascript
Javascript动画的实现原理浅析
Mar 02 Javascript
JQuery select(下拉框)操作方法汇总
Apr 15 Javascript
JavaScript操作Cookie方法实例分析
May 27 Javascript
vue-cli创建的项目,配置多页面的实现方法
Mar 15 Javascript
vue2.0基于vue-cli+element-ui制作树形treeTable
Apr 30 Javascript
详解小程序之简单登录注册表单验证
May 13 Javascript
Vue.js实现立体计算器
Feb 22 Javascript
解决antd日期选择组件,添加value就无法点击下一年和下一月问题
Oct 29 Javascript
Jqprint实现页面打印
Jan 06 #Javascript
JS使用正则截取两个字符串之间的字符串实现方法详解
Jan 06 #Javascript
jQuery EasyUi 验证功能实例解析
Jan 06 #Javascript
jQuery编写网页版2048小游戏
Jan 06 #Javascript
利用JQuery实现datatables插件的增加和删除行功能
Jan 06 #Javascript
javascript正则表达式模糊匹配IP地址功能示例
Jan 06 #Javascript
bootstrap导航栏、下拉菜单、表单的简单应用实例解析
Jan 06 #Javascript
You might like
php时间不正确的解决方法
2008/04/09 PHP
php删除txt文件指定行及按行读取txt文档数据的方法
2017/01/30 PHP
PHP常用操作类之通信数据封装类的实现
2017/07/16 PHP
node.js中的fs.realpath方法使用说明
2014/12/16 Javascript
JavaScript模拟实现继承的方法
2015/03/30 Javascript
JavaScript函数的调用以及参数传递
2015/10/21 Javascript
JavaScript如何获取数组最大值和最小值
2015/11/18 Javascript
三个js循环的关键字示例(for与while)
2016/02/16 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
AngularJS使用指令增强标准表单元素功能
2016/07/01 Javascript
javascript运算符——位运算符全面介绍
2016/07/14 Javascript
判断横屏竖屏(三种)
2017/02/13 Javascript
Vue组件模板形式实现对象数组数据循环为树形结构(实例代码)
2017/07/31 Javascript
js使用highlight.js高亮你的代码
2017/08/18 Javascript
vue.js语法及常用指令
2017/10/29 Javascript
微信小程序页面跳转功能之从列表的item项跳转到下一个页面的方法
2017/11/27 Javascript
使用node打造自己的命令行工具方法教程
2018/03/26 Javascript
JavaScript遍历DOM元素的常见方式示例
2019/02/16 Javascript
[04:02]DOTA2上海特锦赛小组赛第二日recap精彩回顾
2016/02/28 DOTA
在Python web中实现验证码图片代码分享
2017/11/09 Python
python之DataFrame实现excel合并单元格
2021/02/22 Python
Python使用re模块实现信息筛选的方法
2018/04/29 Python
Python切片操作深入详解
2018/07/27 Python
django解决跨域请求的问题
2018/11/11 Python
树莓派+摄像头实现对移动物体的检测
2019/06/22 Python
python提取log文件内容并画出图表
2019/07/08 Python
Python实现微信机器人的方法
2019/09/06 Python
keras绘制acc和loss曲线图实例
2020/06/15 Python
20行Python代码实现一款永久免费PDF编辑工具的实现
2020/08/27 Python
高中生自我鉴定范文
2013/10/30 职场文书
25岁生日感言
2014/01/13 职场文书
党员2014两会学习心得体会
2014/03/17 职场文书
2014年学校后勤工作总结
2014/12/06 职场文书
大队委员竞选稿
2015/11/20 职场文书
2016年社区创先争优活动总结
2016/04/05 职场文书
分享:关于学习的励志名言赏析
2019/08/16 职场文书