为什么这段使用setTimeout/clearTimeout的JS代码输出0 1 2而非0 1 2 3?
为什么这段代码只输出
0 1 2 而不是 0 1 2 3? 这问题的核心在于**var 声明的变量作用域和定时器ID被意外覆盖**这两个点,咱们一步步拆解:
1. var tc 的作用域问题
你用 var 声明了 tc,它属于整个 fn1 函数的作用域,不是循环块的局部变量。所以在四次循环里,每次都会把 tc 重新赋值为新的 setTimeout 返回的定时器ID——等循环全部执行完,tc 最终保存的是第四次循环创建的定时器的ID。
2. 定时器的执行与清除逻辑
四个 setTimeout 都设置了10ms延迟,会在同步的循环代码执行完后,几乎同时进入事件队列等待执行。但第一个触发的回调是 i=0 的那个,它里面调用了 clearTimeout(tc)——这时候 tc 已经是第四个定时器的ID了,所以直接把第四个定时器给清除了,导致它的回调永远不会执行。
而 i=1 和 i=2 的回调执行时,clearTimeout(tc) 其实是在尝试清除已经被干掉的第四个定时器,所以不会产生任何影响,它们能正常输出对应的值。
修复方案
如果想让四个值都输出,最简单的办法是把 var tc 改成 let tc,让 tc 成为循环块的局部变量,每个迭代都有独立的 tc,这样回调里清除的是当前迭代创建的定时器(不过其实这里你可能不需要 clearTimeout,如果只是想输出所有值,去掉 clearTimeout(tc) 也能解决问题):
(function fn1(){ for (var i = 0; i < 4; i++) { let tc=setTimeout(function(i){ console.log(i); clearTimeout(tc); }, 10, i); } })();
内容的提问来源于stack exchange,提问作者Ekil
相关产品推荐
相关产品推荐

