如何解决jQuery定时创建DOM元素时的索引值错误问题?
修复setTimeout循环中索引值传递错误的方案
嘿,这个问题我太熟了!这是典型的闭包作用域陷阱——当你在for循环里用setTimeout时,所有的回调函数共享同一个var i变量。等定时器触发的时候,循环早就执行完了,i已经变成5了,所以每个createEle拿到的都是最后这个值,导致所有div都显示5。
下面给你三种靠谱的修复方法,任选其一就行:
方法1:用立即执行函数(IIFE)创建独立作用域
通过IIFE把每次循环的i值“固定”在一个独立的作用域里,这样每个回调函数绑定的都是当前迭代的数值:
$(document).ready(function() { for (var i = 0; i < 5; i++) { // 立即执行函数,把当前i作为参数传入 (function(currentIndex) { setTimeout(function() { createEle(currentIndex); }, i * 1000); })(i); } }); function createEle(value) { var d = $("<div></div>"); d.addClass("d"); d.html(value); $("#container").append(d); }
方法2:用ES6的let声明变量
let在for循环里会为每一次迭代创建一个全新的变量绑定,天然避免了闭包陷阱,代码最简洁:
$(document).ready(function() { // 把var换成let,每个迭代的i都是独立的 for (let i = 0; i < 5; i++) { setTimeout(function() { createEle(i); }, i * 1000); } }); function createEle(value) { var d = $("<div></div>"); d.addClass("d"); d.html(value); $("#container").append(d); }
方法3:利用setTimeout的第三个参数
现代浏览器支持给setTimeout传递额外参数,这些参数会直接作为回调函数的入参,不用依赖闭包:
$(document).ready(function() { for (var i = 0; i < 5; i++) { // 第三个参数i会传给回调函数的currentIndex setTimeout(function(currentIndex) { createEle(currentIndex); }, i * 1000, i); } }); function createEle(value) { var d = $("<div></div>"); d.addClass("d"); d.html(value); $("#container").append(d); }
配套的CSS和HTML代码保持不变:
.d { height: 20px; color: white; background: red; margin-bottom: 20px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="container"> </div>
内容的提问来源于stack exchange,提问作者peterHasemann
相关产品推荐
相关产品推荐

