The infamous JavaScript loop issue arises when attempting to attach event handlers to dynamically generated elements using a loop. In the following snippet:
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); } }
When any of the generated links is clicked, the alert always displays "link 5." This is because JavaScript's variables defined with var are function-scoped, not block-scoped. When the loop concludes, i holds the value 5, and all the inner functions reference it, leading to the uniform output.
The corrected solution lies in capturing the value of i within a closure. Consider this snippet:
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); } }
In this case, num is bound to the current value of i for each iteration. When the inner function is executed, num is consistently set to the value of i at the moment of loop execution.
Furthermore, an efficient alternative exists that leverages the DOM node for storing data:
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); } }
By attaching information to the DOM element itself, the need for extra function objects is circumvented, improving efficiency.
The above is the detailed content of Why Does My JavaScript Loop Always Output the Final Value of the Counter Variable When Attaching Event Handlers?. For more information, please follow other related articles on the PHP Chinese website!