getElementsByClassName
возвращает живую коллекцию, что означает, что если класс элемента в коллекции изменяется , пока вы выполняете итерацию по нему , или если вы добавляете другой элементс этим классом для DOM, то индекс, на котором вы находитесь (например, если i
равен 2
), может больше не ссылаться на старый элемент там - он может ссылаться на следующий элемент в коллекции или на предыдущийпункт, или это может быть даже undefined
.Поведение довольно неинтуитивно, поэтому я бы предложил вместо этого использовать querySelectorAll
, который возвращает static NodeList
, который не изменится, пока вы выполняете его.
const compilingElts = document.querySelectorAll('.compiling');
Другие преимущества querySelectorAll
:
Строка селектора, принимаемая в качестве аргумента, может быть очень гибкой - она не ограничивается только классами
В более новых браузерах вы можете вызывать forEach
непосредственно на NodeList
, что устраняет необходимость в ручной итерации и отслеживании признаков:
compilingElts.forEach((elm) => {
const randTime = Math.round(Math.random() * (2000 - 500)) + 500;
setTimeout(() => {
switchToReady(elm);
}, randTime);
});
Методы массива гораздо приятнее работать, чем циклы for
во многих случаях.Один из способов достижения аналогичной функциональности в старых браузерах с использованием HTMLCollection
, сгенерированного из getElementsByClassName
, заключается в использовании Array.prototype.forEach
:
Array.prototype.forEach.call(
compilingElts,
(elm) => {
// do stuff with elm
}
);
(вместо него используется комбинация [].forEach.call
, которая выполнитто же самое с меньшим количеством кода, но ссылка на Array.prototype
немного яснее IMO)