HTMLCollection и NodeList

Коллекции элементов DOM-дерева. Похожие, но отличающиеся.

Время чтения: меньше 5 мин

Кратко

Скопировано

HTMLCollection и NodeList — это очень похожие на массив коллекции. Они хранят элементы веб-страницы (узлы DOM). NodeList может хранить любые типы узлов, а HTMLCollection — только узлы HTML элементов. К элементам коллекций можно обращаться по индексу, но у них нет привычных методов массива.

HTMLCollection возвращают методы getElementsByTagName() и getElementsByClassName().

NodeList возвращают метод querySelectorAll() и свойство childNodes.

Полный список всех методов, возвращающих типы NodeList или HTMLCollection можно узнать в стандарте DOM.

Как понять

Скопировано

HTMLCollection возвращают методы, которые работают с DOM — представлением HTML-кода страницы в JavaScript.

Полученная один раз коллекция всегда остаётся актуальной — JavaScript будет обновлять её в случае, если на странице появляется подходящий элемент. Поэтому HTMLCollection называют «живой» коллекцией.

Например, единожды получив коллекцию мы можем не заботиться о её поддержке:

Открыть демо в новой вкладке

NodeList работает почти так же, как и HTMLCollection.

Разница:

  1. NodeList может хранить любые типы узлов, например текстовые узлы и комментарии, а HTMLCollection — только узлы HTML элементов;
  2. HTMLCollection позволяет обращаться к элементам не только по индексу, но и по имени с помощью метода namedItem;
  3. NodeList может быть не только «живой» коллекцией, но и статической. Такая коллекция не обновляется при появлении на странице новых элементов.

«Живой» NodeList возвращают метод getElementsByName() и свойство childNodes.

Статический NodeList возвращает метод querySelectorAll().

На практике

Скопировано

Николай Лопин советует

Скопировано

🛠 Используй индексы для получения отдельных элементов коллекции:

        
          
          const paragraphs = document.getElementsByTagName('p')console.log(paragraphs[0])
          const paragraphs = document.getElementsByTagName('p')
console.log(paragraphs[0])

        
        
          
        
      

🛠 Если нужно обойти все элементы в цикле, то можно написать классический цикл for:

        
          
          const paragraphs = document.getElementsByTagName('p')for (let i = 0; i < paragraphs.length; ++i) {  console.log(paragraphs[i].id)  // печатаем значение атрибута id элемента}
          const paragraphs = document.getElementsByTagName('p')
for (let i = 0; i < paragraphs.length; ++i) {
  console.log(paragraphs[i].id)
  // печатаем значение атрибута id элемента
}

        
        
          
        
      

Другой вариант — воспользоваться синтаксисом for..of:

        
          
          const paragraphs = document.getElementsByTagName('p')for (let item of paragraphs) {  console.log(item.id)}
          const paragraphs = document.getElementsByTagName('p')
for (let item of paragraphs) {
  console.log(item.id)
}

        
        
          
        
      

🛠 При создании цикла над HTMLCollection убедитесь, что подходящие элементы не добавляются или удаляются со страницы в момент работы цикла. Так как коллекция живая, её обновление во время цикла может создать бесконечный цикл.

🛠 Если очень нужны методы массива, то преобразуйте HTMLCollection или NodeList в массив с помощью Array.from().

        
          
          const paragraphs = document.getElementsByTagName('p')let array = Array.from(paragraphs)console.log(array.pop())
          const paragraphs = document.getElementsByTagName('p')
let array = Array.from(paragraphs)

console.log(array.pop())