Странное поведение при переборе HTMLCollection из getElementsByClassName
Я написал функцию для изменения класса элементов, чтобы изменить их свойства. По какой-то причине изменились только некоторые элементы. Мне понадобилось несколько часов, чтобы найти решение, но мне это показалось странным. Возможно, вы можете объяснить это мне.
Это не работает:
function replace(){
var elements = document.getElementsByClassName('classOne');
for (var i = 0; i < elements.length; i++) {
elements[i].className = 'classTwo';
}
}
См. JSFiddle: затрагивается только каждый второй элемент; только каждый второй красный элемент меняет цвет на синий.
Поэтому я изменил окончательное выражение цикла for
, чтобы больше не увеличивать i
:
function replace(){
var elements = document.getElementsByClassName('classOne');
for (var i = 0; i < elements.length; i) { // Heres the difference
elements[i].className = 'classTwo';
}
}
Это хорошо работает! Похоже, что вызывается push
и никакого увеличения не требуется. Это нормально? Это отличается от примеров, которые я видел.
Ответы
Ответ 1
Что происходит, это странный побочный эффект. Когда вы переназначаете className
для каждого элемента elements
, элемент удаляется из массива! (На самом деле, как указывает @user2428118, elements
- объект, подобный массиву, а не массив. См. этот поток для разницы.) Это потому, что он не более длинное имя класса classOne
. Когда ваш цикл выходит (во втором случае), массив elements
будет пустым.
Вы можете написать свой цикл как:
while (elements.length) {
elements[0].className = 'classTwo'; // removes elements[0] from elements!
}
В вашем первом случае, увеличивая i
, вы пропускаете половину (оригинальных) элементов с классом classOne
.
Отличный вопрос, кстати. Хорошо изучены и понятны.
Ответ 2
getElementsByClassName
возвращает NodeList. Коллекция NodeList - это живая коллекция, что означает, что изменение документа влияет на коллекцию. более
Ответ 3
Или верните цикл, начиная с длины-1 и опустившись до 0