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中执行函数进行传参数时推荐的做法是使用“闭包”。
相关阅读
正则表达式/正则表达式主体/修饰符(可选)修饰符:i —— 大小写不敏感匹配g —— 全局匹配m —— 多行匹配常用 (正则内容换为字符串也
JSP如何读取MySql中MEDIUMBLOB字符串,并显示?实现向MYSQL数据库中存储或提取图片文件一些情况下,需要向数据库中存储一些2进制文件,比
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