JavaScript setTimeout 使用闭包实现定时打印数值

作者:木棉时间:2026-10-29 18:58:48浏览:82

本文通过 setTimeout 定时打印数值的示例,分析直接使用循环变量导致的执行时机与值共享问题。对比全局变量方案后,重点讲解利用闭包为每次定时器调用创建独立作用域的方法,确保每个定时任务能获取正确的循环变量值,并提供了封装函数的实用技巧。

setTimeout 定时打印示例分析

本文通过 setTimeout 实现一个按时间间隔依次打印数值的示例。早期常有人觉得用 JS 实现这种能力比较牵强,这其实是对 JS 特性理解不足。虽然使用 setInterval 实现相对简单,但本文旨在探讨如何使用 setTimeout 达成相同效果。我们从最基础的思路开始分析,通常会写出如下代码。


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

这段代码虽然依次打印了每个 i 的值 0, 1, 2, 3, 4,但执行时间并未如预期那样产生间隔。原因在于 console.log() 是立即执行的方法调用,在调用该方法时,参数 i 的值已经被确定并立即输出,因此没有达到预期的延时效果。

接下来我们查看另一种写法。


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

变量共享与全局变量方案

这里使用一个匿名函数包裹 console.log 来打印 i,但由于 i 是共享的变量,在第一个 setTimeout 触发之前,for 循环已经执行完毕,此时 i 的值已变为 5。因此,所有定时器最终都会打印 5,共打印四次。针对此问题,我们先看第一种解决方案:


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

这里引入另一个全局变量来存储值,每执行一次函数 abc,j 就加一。当执行到 setTimeout 时,调用 abc 函数,似乎能达到预期效果。然而,使用全局变量容易导致值被意外修改或产生命名冲突等问题。第二种方案则再次引入闭包函数,因为闭包在每次创建时都会拥有独立的空间来存储唯一的值。基于此思路,我们将代码改写如下。


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

利用闭包解决作用域问题

我们将 for 循环中 i 的每一次执行值,传递给不同创建的闭包函数。这样,每个闭包函数内部存储的 i 值互不相同,从而达到了我们预期的定时打印不同数值的结果。

补充说明:使用闭包对 setTimeout 进行简单封装。

闭包封装与字符串拼接陷阱

在编写 JS 脚本时,经常会遇到需要拼接字符串来调用函数的情况,例如调用 setTimeout。


var msgalert="test"; 
 function TestAlert(msg) 
   { 
    alert(msg) 
   } 
    
   $(document).ready(function () { 
  $("#btnCancel").click(function (e) { 
    setTimeout("TestAlert("+msgalert+")",1000); 
    }); 
}) 

经过长时间排查,发现无法弹出对话框的原因是少了一对单引号。


$(document).ready(function () { 
  $("#btnCancel").click(function (e) { 
    setTimeout("TestAlert('"+msgalert+"')",1000); 
    }); 
}) 

这种字符串拼接的写法容易出错,且难以检查。如果使用闭包则可以完全避免此类问题,改写方式如下。


 var msgalert="test"; 
  function dalayAlert(msg ,time){  
  setTimeout( 
  TestAlert(msg), 
  time 
  ); 
  }  
 function TestAlert(msg) 
 { 
  alert(msg) 
 } 
$(document).ready(function () {   
$("#btnCancel").click(function (e) { 
   dalayAlert(msgalert,1000) 
 }); 

由于使用了闭包,代码逻辑变得简单,且检查错误也变得更加容易。

作者最新文章