JavaScript中for循环绑定onclick无法正确获取索引的问题
解决JavaScript循环中点击事件捕获索引错误的问题
这是个非常常见的JavaScript闭包陷阱问题,我来帮你拆解原因和解决办法~
问题原因
你在for循环里使用箭头函数作为onclick的回调,但箭头函数不会创建自己的作用域,它会捕获外层作用域中变量i的引用,而不是当前循环迭代时i的具体值。当整个循环执行完毕后,i的值已经变成了Contacts.length(也就是2),所以不管你点击哪个FONT元素,最终打印的都是这个循环结束后的i值。
解决方案
这里有几种简单有效的解决方式,你可以根据自己的习惯选择:
1. 把var改成let(最简洁的现代方案)
利用ES6中let的块级作用域特性,每次循环迭代都会生成一个新的i变量,每个箭头函数捕获的都是当前迭代的那个i的引用:
Contacts.push("test1 test 4232352"); Contacts.push("test2 test2 5435345"); // 将var替换为let,让每个循环迭代拥有独立的i变量 for(let i = 0; i < Contacts.length; i++){ var res = Contacts[i].split(" "); var font = document.createElement("FONT"); font.innerHTML = res[0] + " " + res[1]; font.style.marginLeft = "10px"; font.onclick = () => { console.log(i); }; document.getElementById("contacts_collection").appendChild(font); }
2. 使用立即执行函数(IIFE)创建独立作用域
如果需要兼容ES5及更早的环境,可以用立即执行函数把当前i的值保存下来,形成独立的作用域:
Contacts.push("test1 test 4232352"); Contacts.push("test2 test2 5435345"); for(var i = 0; i < Contacts.length; i++){ var res = Contacts[i].split(" "); var font = document.createElement("FONT"); font.innerHTML = res[0] + " " + res[1]; font.style.marginLeft = "10px"; // 通过IIFE传递并保存当前迭代的i值 font.onclick = ((currentIndex) => { return () => { console.log(currentIndex); }; })(i); document.getElementById("contacts_collection").appendChild(font); }
3. 改用forEach循环
forEach的回调函数本身会为每个数组元素创建独立的作用域,直接就能拿到当前元素的索引:
Contacts.push("test1 test 4232352"); Contacts.push("test2 test2 5435345"); Contacts.forEach((contact, i) => { var res = contact.split(" "); var font = document.createElement("FONT"); font.innerHTML = res[0] + " " + res[1]; font.style.marginLeft = "10px"; font.onclick = () => { console.log(i); }; document.getElementById("contacts_collection").appendChild(font); });
额外小提示
另外要提一句:<FONT>标签是HTML4的过时标签了,现在更推荐使用<span>或者<div>配合CSS样式来实现相同的效果,这样更符合现代HTML的规范哦~
内容的提问来源于stack exchange,提问作者Jeffrey
相关产品推荐
相关产品推荐

