当尝试使用循环将事件处理程序附加到动态生成的元素时,就会出现臭名昭著的 JavaScript 循环问题。在以下代码片段中:
function addLinks() { for (var i = 0, link; i < 5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function () { alert(i); // WRONG: i will always be 5 }; document.body.appendChild(link); } }
单击任何生成的链接时,警报始终显示“链接 5”。这是因为用 var 定义的 JavaScript 变量是函数作用域的,而不是块作用域的。当循环结束时,i 保持值 5,所有内部函数都会引用它,从而得到统一的输出。
更正的解决方案在于捕获闭包内 i 的值。考虑这个片段:
function addLinks() { for (var i = 0, link; i < 5; i++) { link = document.createElement("a"); link.innerHTML = "Link " + i; link.onclick = function (num) { // Closure around i return function () { alert(num); // num retains its original value }; }(i); // Execute the outer function immediately to capture i document.body.appendChild(link); } }
在这种情况下,num 绑定到每次迭代的 i 的当前值。当执行内部函数时,num 始终设置为循环执行时 i 的值。
此外,存在一种利用 DOM 节点存储数据的有效替代方案:
function linkListener() { alert(this.i); } function addLinks() { for (var i = 0; i < 5; ++i) { var link = document.createElement('a'); link.appendChild(document.createTextNode('Link ' + i)); link.i = i; link.onclick = linkListener; document.body.appendChild(link); } }
通过将信息附加到 DOM 元素本身,避免了对额外函数对象的需求,从而提高了效率。
以上是为什么我的 JavaScript 循环在附加事件处理程序时总是输出计数器变量的最终值?的详细内容。更多信息请关注PHP中文网其他相关文章!