必威体育Betway必威体育官网
当前位置:首页 > IT技术

关于JS中的setTimeout()

时间:2019-08-12 09:43:15来源:IT技术作者:seo实验室小编阅读:74次「手机版」
 

settimeout

1、settimeout()基础

setTimeout函数用来指定某个函数或某段代码,在多少毫秒之后执行。它返回一个整数,表示定时器的编号,以后可以用来取消这个定时器。

var timerId = setTimeout(func|code, delay)

上面代码中,setTimeout函数接受两个参数,第一个参数func|code是将要推迟执行的函数名或者一段代码,第二个参数delay是推迟执行的毫秒数。·

需要注意的是,推迟执行的代码必须以字符串的形式,放入setTimeout,因为引擎内部使用eval函数,将字符串转为代码。如果推迟执行的是函数,则可以直接将函数名,放入setTimeout。一方面eval函数有安全顾虑,另一方面为了便于javaScript引擎优化代码,setTimeout方法一般总是采用函数名的形式,就像下面这样。

function func(){
  console.log(2);
}
setTimeout(func,1000);
// 或者
setTimeout(function (){console.log(2)},1000);

2、关于setTimeout执行的几个代码片段,看一下执行结果是什么?

for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000 * i);
}

输出:setTimeout 会延迟执行,那么执行到 console.log 的时候,其实 i 已经变成 5 了,所以“应该是开始输出一个 5,然后每隔一秒再输出一个 5,一共 5 个 5。”

怎么改才能输出 0 到 4 呢?(用闭包)

for (var i = 0; i < 5; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i);
    }, i * 1000);
  })(i);
}

输出:0、1、2、3、4。

如果改成这个样子,输出什么:

for (var i = 0; i < 5; i++) {
  setTimeout((function(i) {
    console.log(i);
  })(i), i * 1000);
}

输出:这里给 setTimeout 传递了一个立即执行函数。setTimeout 接受函数或者字符串作为参数,那么这里立即执行函数应该是个 undefined ,也就是说等价于:·setTimeout(undefined, ...); 而立即执行函数会立即执行,所以应该立马输出0到4。

3、setTimeout()中回调函数中的this

如果被setTimeout推迟执行的回调函数是某个对象的方法,那么该方法中的this关键字将指向全局环境,而不是定义时所在的那个对象。

var x = 1;

var o = {
  x: 2,
  y: function(){
    console.log(this.x);
  }
};
setTimeout(o.y,1000);// 1

上面代码输出的是1,而不是2,这表示o.y的this所指向的已经不是o,而是全局环境了。

再看一个不容易发现错误的例子。·

function User(login) {
  this.login = login;
  this.sayHi = function() {
    console.log(this.login);
  }
}
var user = new User('John');
setTimeout(user.sayHi, 1000);

上面代码只会显示undefined,因为等到user.sayHi执行时,它是在全局对象中执行,所以this.login取不到值。

为了防止出现这个问题,一种解决方法是将user.sayHi放在匿名函数中执行。

setTimeout(function() {
  user.sayHi();
}, 1000);

上面代码中,sayHi是在user作用域内执行,而不是在全局作用域内执行,所以能够显示正确的值。

另一种解决方法是,使用bind方法,将绑定sayHi绑定在user上面。

setTimeout(user.sayHi.bind(user), 1000);

4、setTimeout传参数

有如下要求的例子,每间隔5000*i 秒执行一段程序

function send_ajax(i){
    console.log(new Date()+" "+i);
}

for(var i=0;i<5;i++){
    setTimeout(send_ajax(i),i*5000);
}

实际输出,如下没有达到我们的目标。因为你传递给了setTimeout一段函数调用send_ajax(i)的返回值 ,在本例中相当于setTimeout(undefine,arg1), 而send_ajax(i)会立即执行,随后什么也不会再发生。

Fri Oct 05 2018 16:11:42 GMT+0800 (中国标准时间) 0
Fri Oct 05 2018 16:11:42 GMT+0800 (中国标准时间) 1
Fri Oct 05 2018 16:11:42 GMT+0800 (中国标准时间) 2
Fri Oct 05 2018 16:11:42 GMT+0800 (中国标准时间) 3
Fri Oct 05 2018 16:11:42 GMT+0800 (中国标准时间) 4

因为setTimeout接收函数名或代码片段,所以改成如下的形式是可以的:

​
function send_ajax(i){
    console.log(new Date()+" "+i);
}

for(var i=0;i<5;i++){ 
	setTimeout("send_ajax("+i+")",i*5000);
}

输出结果如下,基本满足了我们的要求:

Fri Oct 05 2018 21:39:25 GMT+0800 (中国标准时间) 0
Fri Oct 05 2018 21:39:30 GMT+0800 (中国标准时间) 1
Fri Oct 05 2018 21:39:35 GMT+0800 (中国标准时间) 2
Fri Oct 05 2018 21:39:40 GMT+0800 (中国标准时间) 3
Fri Oct 05 2018 21:39:45 GMT+0800 (中国标准时间) 4

为了把每次调用的参数用一种较为优雅的形式来传递到setTimeout的执行函数,结合本文章前面第一节分析的那样,可以使用闭包。

function send_ajax(i){
    console.log(new Date()+" "+i);
}
for(var i=0;i<5;i++){ 
	(function(i){
		setTimeout(function(){send_ajax(i)},i*5000);
	})(i);
}
输出:(因为使用闭包,使用局部变量保持作用域外的一个引用)
Fri Oct 05 2018 21:47:00 GMT+0800 (中国标准时间) 0
Fri Oct 05 2018 21:47:05 GMT+0800 (中国标准时间) 1
Fri Oct 05 2018 21:47:10 GMT+0800 (中国标准时间) 2
Fri Oct 05 2018 21:47:15 GMT+0800 (中国标准时间) 3
Fri Oct 05 2018 21:47:20 GMT+0800 (中国标准时间) 4

或者:

function send_ajax(i){
    console.log(new Date()+" "+i);
}
function _send_ajax(_i){
    return function(){
             send_ajax(_i);
       }
}
for(var i=0;i<5;i++){ 
	setTimeout(_send_ajax(i),i*5000);
}
输出:(还是使用闭包的方式来解决,虽然传递给了一个立即执行的函数,但是这个函数的返回值却又是一个函数,保留了调用时的局部变量i)
VM5549:2 Fri Oct 05 2018 22:11:07 GMT+0800 (中国标准时间) 0
VM5549:2 Fri Oct 05 2018 22:11:12 GMT+0800 (中国标准时间) 1
VM5549:2 Fri Oct 05 2018 22:11:17 GMT+0800 (中国标准时间) 2
VM5549:2 Fri Oct 05 2018 22:11:22 GMT+0800 (中国标准时间) 3
VM5549:2 Fri Oct 05 2018 22:11:27 GMT+0800 (中国标准时间) 4

也附上经常容易出错的另外两种写法:

错误写法一:

function send_ajax(i){
    console.log(new Date()+" "+i);
}
for(var i=0;i<5;i++){ 
	setTimeout(function(){send_ajax(i)},i*5000);
}
输出:(因为setTimeout 会延迟执行,那么执行到 console.log 的时候,其实 i 已经变成 5 了)
Fri Oct 05 2018 21:44:27 GMT+0800 (中国标准时间) 5
Fri Oct 05 2018 21:44:32 GMT+0800 (中国标准时间) 5
Fri Oct 05 2018 21:44:37 GMT+0800 (中国标准时间) 5
Fri Oct 05 2018 21:44:42 GMT+0800 (中国标准时间) 5
Fri Oct 05 2018 21:44:47 GMT+0800 (中国标准时间) 5

错误写法二:

function send_ajax(i){
    console.log(new Date()+" "+i);
}
for(var i=0;i<5;i++){ 
	setTimeout(function(i){send_ajax(i)},i*5000);
}
输出:(因为setTimeout的函数的this指针是全局的,所以i在全局范围内执行是undefined)
Fri Oct 05 2018 21:44:01 GMT+0800 (中国标准时间) undefined
Fri Oct 05 2018 21:44:06 GMT+0800 (中国标准时间) undefined
Fri Oct 05 2018 21:44:11 GMT+0800 (中国标准时间) undefined
Fri Oct 05 2018 21:44:16 GMT+0800 (中国标准时间) undefined
Fri Oct 05 2018 21:44:21 GMT+0800 (中国标准时间) undefined

所以对setTimeout中执行函数进行传参数时推荐的做法是使用“闭包”。

相关阅读

js——正则表达式 (引用菜鸟教程)

正则表达式/正则表达式主体/修饰符(可选)修饰符:i —— 大小写不敏感匹配g —— 全局匹配m —— 多行匹配常用 (正则内容换为字符串也

JSP如何读取MySql中MEDIUMBLOB字符串

JSP如何读取MySql中MEDIUMBLOB字符串,并显示?实现向MYSQL数据库中存储或提取图片文件一些情况下,需要向数据库中存储一些2进制文件,比

[FLV.JS]

https://www.zhihu.com/question/53686737 https://github.com/Bilibili/flv.js 1,h5上实现直播的目前已知的最优解决方案,性能不

GET http runtime.js net ERR_ABORTED 404 (Not Found

GET http runtime.js net ERR_ABORTED 404 (Not Found) 第一 把点去掉你应该就会发现 没错了第二 如果你一定要加点的话,看下图操

extjs的apply,applyIf和merge用法及原理剖析

extjs的apply,applyIf和merge都用来操作2个对象并生成新对象,在实现结果上是有区别的,下面来看下他们的区别:先定义2个对象:var obj1

分享到:

栏目导航

推荐阅读

热门阅读