2015-09-25 2 views
4

Когда я загружаю мою страницу, нодлист получает создан, и это выглядит следующим образом:для ... в цикле, не охватывая все свойства?

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

Я создал простой for цикл, который через все эти элементы и удаляет каждый из них из DOM. (Все элементы находятся в <section>)

Вот петля:

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

Но, к концу цикла, Нодлист выглядит следующим образом:

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

не все элементы получили удален. Зачем?

Спасибо.

+1

Поскольку вы меняете коллекцию при прохождении через нее. Допустим, у вас есть три элемента в коллекции '[A, B, C]'. Цикл 'for..in' будет внутренне иметь индексатор для отслеживания текущего элемента. Таким образом, индексатор равен 0 в начале, что указывает на элемент 'A'. Затем вы удаляете первый элемент, а второй элемент - «B», теперь становится первым. Индексатор теперь продвигается и указывает на 1. Теперь элемент в индексе 1, 'C', удаляется. И поскольку вы можете видеть, что элемент с индексом 0, 'B', нетронутым и пропущен. –

ответ

11

Две вещи. Во-первых, не используйте for ... in, когда вы повторяете числовые индексы; используйте простую петлю for. Тогда вам не понадобится эта проверка isNaN(), и это в целом безопаснее.

Вторая проблема заключается в том, что при удалении дочернего элемента вы изменяете длину списка. Если удалить ребенка 0, то ребенок, который имел обыкновение быть ребенок 1 ребенок становится 0. Таким образом, то, что вы действительно хотите простой while цикл:

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

или, проще:

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

следует также отметить, (при условии, что вы работаете с HTML DOM), что легче очистить все дочерние узлы элемента, просто взрывая его с помощью .innerHTML:

videoTitlesElement.innerHTML = ""; 
+0

Простейший случай почти корректен, но здесь: '.removeChild (firstChild)' 'firstChild' не определен. – pawel

+0

@pawel oh durr ...спасибо, что заметили, я исправлю это – Pointy

+0

Спасибо! Отличное объяснение. «Очистка» .innerHTML не самая лучшая в моем случае, и я также читаю, что удаление элементов один за другим, как правило, намного быстрее. –

3

Если вы посмотрите на свои результаты, вы заметите, что пропускаете каждый второй предмет.

Если вы представляете себе это как цикл for с итератором, вы каждый раз увеличиваете свой итератор, но удаляете элемент из той же коллекции, прежде чем увеличивать его. Это означает, что элемент, который был в индексе 1 при первом запуске цикла, находится в индексе 0 после удаления первого элемента в массиве. Поэтому, когда вы смотрите на индекс 1, вы пропустили этот элемент. Это продолжается до конца цикла, поэтому вы пропускаете каждый второй элемент.

4

Переименованный список (videoTitlesElement.childNodes) мутируется во время итерации. Попробуйте выполнить повторную копию копии оригинального списка:

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

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

Обратите внимание, что использование 'for..in' для итерации над массивами недовольно. – pawel

Смежные вопросы