Why does removing an element with javascript prevent iteration of elements?

后端 未结 1 1947
余生分开走
余生分开走 2021-01-21 13:01

I am trying to replace all text fields on a page with labels.

function replaceInputTextFieldsWithValues() {

    var inputFields = document.getElementsByTagName(         


        
1条回答
  •  清酒与你
    2021-01-21 13:59

    What you get back from getElementsByTagName is an HTMLCollection, which is live. (This is true for the other getElementsByXYZ methods, but not querySelectorAll.) That means if you remove the element at index 0, the HTMLCollection's length will go down and you'll have a new element at index 0 instead of the one you just removed.

    Just work your way through it backward and you'll be fine:

    for(var i = inputFields.length - 1; i >= 0; i--) {
        // ...
    }
    

    Alternately, convert the HTMLCollection into an array and then loop through the array. (See the live example and code below).

    Edit: Or, as Chris Shouts points out in the comments, you can just make use of the changing length, but it's not quite as simple as Chris' suggestion because you're only removing the elements sometimes. It would look like this:

    var inputFields = document.getElementsByTagName("input");
    var i = 0;
    while (i < inputFields.length) {
        if(inputFields[i].getAttribute("type")== "text") {
           // Remove it and DON'T increment `index`
        }
        else {
           // Skip this one by incrementing `index`
           ++index;
        }
    }
    

    Which of these three approaches to use will depend on the situation. Copying to an array gives you a nice static dataset to work with, and if you make sure to release the reference to the HTMLCollection, you're giving the browser the opportunity to realize it doesn't have to keep that list up-to-date when things change, which could reduce overhead. But you're copying the references briefly, which increases overhead a bit. :-)


    Additional: Here's an example showing this effect, and also showing a fairly efficient (but obscure) way to create an array from a HTMLCollection:

    HTML:

    • LI0
    • LI1
    • LI2

    JavaScript:

    var lilist, liarray;
    
    // Get the HTMLCollection, which is live
    lilist = document.getElementsByTagName('li');
    
    // Create an array of its elements
    liarray = Array.prototype.slice.call(lilist, 0);
    
    // Show initial length of both
    display("lilist.length = " + lilist.length);   // Shows 3
    display("liarray.length = " + liarray.length); // Shows 3
    
    // Show what the 0th element of both is (both show "LI0" in the live example)
    display("lilist[0].innerHTML = " + lilist[0].innerHTML);   // Shows LI0
    display("liarray[0].innerHTML = " + liarray[0].innerHTML); // Shows LI0
    
    // Remove the first list item
    display("Removing item 0");
    lilist[0].parentNode.removeChild(lilist[0]);
    
    // Show the length of both, note that the list's length
    // has gone down, but the array's hasn't
    display("lilist.length = " + lilist.length);    // Shows 2, not 3
    display("liarray.length = " + liarray.length);  // Still shows 3
    
    // Show what the 0th element of both *now* is
    display("lilist[0].innerHTML = " + lilist[0].innerHTML);   // Shows LI1 now
    display("liarray[0].innerHTML = " + liarray[0].innerHTML); // Still shows LI0
    

    Live copy

    0 讨论(0)
提交回复
热议问题