使用for循环与setTimeout显示姓名时出现undefined及i值异常的问题
问题原因与修复方案
问题原因
你遇到的问题根源是变量作用域和闭包的延迟绑定:
- 用
var声明的变量i属于函数级作用域,整个members函数里只有一个i的引用。 setTimeout的回调是异步执行的,3秒后才会触发,但此时for循环已经完全跑完,i的值已经变成了4(循环条件是i < arr.length,当i等于4时停止循环)。- 回调执行时访问的
i是最终的4,而arr[4]不存在,所以返回undefined。
修复方法
方法1:使用let声明循环变量(ES6+推荐)
let会创建块级作用域,每次循环都会生成独立的i变量,回调会绑定当前循环的i值:
function members() { var arr = ["Joseph","John","Kumar","Shiva"]; for(let i = 0; i < arr.length; i++) { setTimeout(function() { console.log("Member = " + i + ". " + arr[i]); document.getElementById("Names").innerHTML = "Member = " + i + ". " + arr[i]; }, 3000); } } members();
注:这样所有回调会在3秒后同时执行,最终只会显示最后一个成员。如果想每隔3秒依次显示一个,把延迟时间改成3000 * (i + 1)即可。
方法2:用立即执行函数(IIFE)创建独立作用域
在外层包裹立即执行函数,把当前i作为参数传递进去,保存当前循环的变量值:
function members() { var arr = ["Joseph","John","Kumar","Shiva"]; var i; for(i = 0; i < arr.length; i++) { (function(currentIndex) { setTimeout(function() { console.log("Member = " + currentIndex + ". " + arr[currentIndex]); document.getElementById("Names").innerHTML = "Member = " + currentIndex + ". " + arr[currentIndex]; }, 3000); })(i); } } members();
方法3:使用forEach遍历数组
forEach的回调本身自带独立作用域,每次遍历的索引和元素都是当前循环的有效值:
function members() { var arr = ["Joseph","John","Kumar","Shiva"]; arr.forEach(function(member, index) { setTimeout(function() { console.log("Member = " + (index + 1) + ". " + member); document.getElementById("Names").innerHTML = "Member = " + (index + 1) + ". " + member; }, 3000); }); } members();
内容的提问来源于stack exchange,提问作者Veeramani R
相关产品推荐
相关产品推荐

