bool3max
bool3max

Reputation: 2865

for...in loop not looping through all properties?

When I load my page, a nodeList gets created, and it looks like this:

[text, h4, text, span, br, input, br, span, br, input, br, span, br, input, br, span, br, input, br]

I created a simple for loop that loops through all these elements and deletes each one of them from the DOM. (all the elements are in a <section>)

Here's the loop:

        for(element in videoTitlesElement.childNodes){
            if(!isNaN(element)){
                videoTitlesElement.removeChild(
                        videoTitlesElement.childNodes[element]);
            }
        }

But, by the end of the loop, the nodeList looks like this:

[h4, span, input, span, input, span, input, span, input]

not all elements got removed. Why?

Thanks.

Upvotes: 4

Views: 1164

Answers (3)

Pointy
Pointy

Reputation: 413727

Two things. First, don't use for ... in when you're iterating through numeric indexes; use a plain for loop. Then you won't need that isNaN() check, and it's generally safer.

The second problem is that when you remove a child, you change the length of the list. If you remove child 0, then the child that used to be child 1 becomes child 0. Thus, what you really want is a simple while loop:

while (videoTitlesElement.childNodes.length)
  videoTitlesElement.removeChild(videoTitlesElement.childNodes[0]);

or, simpler:

while (videoTitlesElement.firstChild)
  videoTitlesElement.removeChild(videoTitlesElement.firstChild);

I should also note (assuming you're working with an HTML DOM) that it's easier to clear out all the child nodes of an element by simply blasting it via .innerHTML:

videoTitlesElement.innerHTML = "";

Upvotes: 12

rjz
rjz

Reputation: 16510

The list being iterated over (videoTitlesElement.childNodes) is being mutated during iteration. Try iterating over a copy of the original list:

var children = [].slice.call(videoTitlesElement.childNodes);

for(element in children){
    if(!isNaN(element)){
         videoTitlesElement.removeChild(videoTitlesElement.childNodes[element]);
    }
}

Upvotes: 4

StriplingWarrior
StriplingWarrior

Reputation: 156524

If you look at your results, you'll note that you're skipping every second item.

If you imagine this as a for loop with an iterator, you're incrementing your iterator each time, but removing an item from the same collection before incrementing again. That means the item that was at index 1 when you first start the loop is at index 0 after you remove the first item in the array. So when you go to look at index 1 you've skipped over that element. This continues until the end of the loop, so you miss every second item.

Upvotes: 3

Related Questions