关于JS中的setTimeout()

本文深入解析了JavaScript中的setTimeout函数,包括其基础用法、执行机制、回调函数中的this问题、参数传递方式,以及如何避免常见错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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中执行函数进行传参数时推荐的做法是使用“闭包”。
 

<think>好的,用户想了解如何在JavaScript中正确使用setTimeout函数,特别是使用方法和示例。首先,我需要回忆setTimeout的基本用法。记得setTimeout用于在指定的延迟后执行一次代码,语法是setTimeout(function, delay, ...args)。可能需要解释参数,比如第一个参数是函数,第二个是毫秒数,后面的参数可以作为传入函数的参数。 接下来,用户可能需要基础示例。比如,延迟显示一条消息,或者执行一个简单的操作。应该给出代码示例,并说明各部分的作用。例如,用匿名函数或者函数名作为第一个参数,还有延迟时间设置。 然后,可能需要提到清除定时器的方法,即clearTimeout,使用返回的timeoutID来取消执行。这时候应该举一个例子,比如设置定时器,然后在某些条件下清除它。 另外,用户可能想知道参数传递。比如如何给回调函数传参,可以通过setTimeout的第三个及以后的参数来实现。这部分需要示例说明,避免用户误解。 还要注意常见的错误,比如直接调用函数而不是传递函数引用。例如,setTimeout(someFunction(), 1000)会立即执行,而不是延迟执行。应该指出正确的方式是传递函数名或匿名函数。 另外,关于this的指向问题,在对象方法中使用setTimeout时,this可能会丢失,需要使用bind或者箭头函数来保持上下文。这也是一个需要注意的点,可能需要举例说明。 用户提供的引用内容提到setTimeout只执行一次,这点需要强调,和setInterval区别开来。如果有需要,可以简要对比两者,但用户当前问题可能不需要深入这个,所以保持重点在setTimeout。 现在要组织这些点,确保结构清晰。先介绍语法,然后基础示例,接着参数传递,清除定时器,常见错误,this指向问题,最后注意事项。每个部分配以代码示例,帮助用户理解。 需要检查语法是否正确,比如使用箭头函数或者传统函数写法的区别。同时,确保示例简单明了,不要过于复杂,让用户容易复制和测试。 最后,生成相关问题,可能涉及setTimeout的执行机制、与事件循环的关系、如何实现重复执行等,但根据用户提供的引用,可能问题应集中在setTimeout本身,比如如何取消、参数传递、this绑定等。</think>### JavaScript setTimeout() 使用详解 #### 基础语法 `setTimeout()` 方法用于在指定延迟时间后执行代码,语法为: ```javascript const timeoutID = setTimeout(functionRef, delay, arg1, arg2, ...) ``` - **functionRef**:要执行的函数或代码字符串(不推荐) - **delay**:延迟时间(毫秒),默认`0` - **arg1, arg2...**:传递给函数的参数(ES6+支持)[^1] #### 基础示例 1. **显示延迟消息**: ```javascript setTimeout(() => { console.log("3秒后显示此消息"); }, 3000); ``` 2. **传递参数**: ```javascript function showMessage(name) { console.log(`Hello ${name}`); } setTimeout(showMessage, 2000, "Alice"); // 输出:Hello Alice(2秒后) ``` #### 取消执行 使用`clearTimeout()`终止定时器: ```javascript const timer = setTimeout(() => { console.log("此消息不会显示"); }, 1000); clearTimeout(timer); // 立即取消定时器 ``` #### 常见错误 1. **立即执行陷阱**: ```javascript // 错误写法:立即执行函数 setTimeout(alert("错误!"), 1000); // 正确写法:传递函数引用 setTimeout(() => alert("正确!"), 1000); ``` 2. **this指向问题**: ```javascript const obj = { name: "Object", showName() { console.log(this.name); } }; // 错误示例(丢失this): setTimeout(obj.showName, 1000); // 输出undefined // 正确方案1:使用箭头函数 setTimeout(() => obj.showName(), 1000); // 正确方案2:使用bind setTimeout(obj.showName.bind(obj), 1000); ``` #### 注意事项 1. 定时器最小延迟≥4ms(浏览器规范) 2. 嵌套5层以上时延迟强制≥4ms[^1] 3. 实际执行时间可能因主线程阻塞延后
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值