使用timer.js结合for循环遍历数组仅输出最后值的问题
解决timer.js结合for循环遍历数组只输出最后一个元素的问题
我太懂这个坑了!这本质上是JavaScript循环变量的作用域问题,再加上timer.js的异步执行特性,就导致所有延迟回调都拿到了同一个变量的最终值。
问题根源
当你用var声明循环变量(比如var i)时,它是函数级作用域的——整个循环里只有一个i变量。当timer的延迟回调触发时,循环早就跑完了,i已经变成了数组的长度,这时候arr[i]取到的自然就是最后一个元素(刚好索引对应上的情况)。
解决方案
下面给你三种可行的解决办法,按需选择:
1. 用let声明循环变量(推荐,ES6+)
let是块级作用域的,每次循环都会创建一个全新的i变量,timer的回调会绑定当前循环的那个i值:
const myArray = ["元素1", "元素2", "元素3", "元素4"]; const myTimer = new Timer(); // 用let声明i,每个循环块都有独立的i for (let i = 0; i < myArray.length; i++) { // 每次延迟递增,比如间隔1秒 myTimer.add(i * 1000, () => { console.log(myArray[i]); }); } myTimer.start();
2. 用立即执行函数(IIFE)创建闭包(兼容ES5)
如果需要支持旧环境,用闭包把每次循环的变量值“固定”下来:
const myArray = ["元素1", "元素2", "元素3", "元素4"]; const myTimer = new Timer(); for (var i = 0; i < myArray.length; i++) { // 立即执行函数,把当前的i作为参数传入 (function(currentIndex) { myTimer.add(currentIndex * 1000, () => { console.log(myArray[currentIndex]); }); })(i); } myTimer.start();
3. 改用数组的forEach方法(更简洁)
forEach的回调函数本身就会为每个迭代创建独立的作用域,不用操心变量问题:
const myArray = ["元素1", "元素2", "元素3", "元素4"]; const myTimer = new Timer(); myArray.forEach((item, index) => { myTimer.add(index * 1000, () => { console.log(item); }); }); myTimer.start();
注意事项
别忘了调用timer.start()——这是timer.js启动整个定时器队列的关键,要是漏掉这一步,所有回调都不会执行哦。
内容的提问来源于stack exchange,提问作者krabbos
相关产品推荐
相关产品推荐

