Подтвердить что ты не робот

Почему forEach не работает для детей?

У меня есть <div> с некоторым дочерним <div>. Например.

<div id="niceParent">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

Я попытался пропустить их с помощью функции forEach, потому что я думал, что document.getElementById("niceParent").children является массивом, так как я могу получить доступ к элементам с помощью

console.log(document.getElementById("niceParent").children[1]);
console.log(document.getElementById("niceParent").children[2]);
console.log(document.getElementById("niceParent").children[3]);
console.log(document.getElementById("niceParent").children[4]);

Следовательно, я попробовал

document.getElementById("niceParent").children.forEach(function(entry) {
  console.log(entry);
});

который не работает. Я получаю

TypeError: document.getElementById(...).children.forEach is not a function

В качестве обходного пути я также попробовал его с гораздо более сложным циклом for..in:

for (var i in document.getElementById("niceParent").children) {
  if (document.getElementById("niceParent").children[i].nodeType == 1) console.log(document.getElementById("niceParent").children[i]);
}

который работал как ожидалось.

Почему?

4b9b3361

Ответ 1

Потому что .children содержит HTMLCollection [MDN], а не массив. Объект HTMLCollection является массивоподобным объектом, который предоставляет свойство .length и имеет числовые свойства, как и массивы, но он не наследуется от Array.prototype и, следовательно, не является массивом.

Вы можете преобразовать его в массив, используя Array.prototype.slice:

var children = [].slice.call(document.getElementById(...).children);

ECMAScript 6 представляет новый API для преобразования итераторов и массивоподобных объектов в реальные массивы: Array.from [MDN]. Используйте это, если возможно, так как это делает намерение намного яснее.

var children = Array.from(document.getElementById(...).children);

Ответ 2

Element.children не является массивом. Это объект, который называется HTMLCollection. У них нет методов массивов (хотя они имеют свойство length).

Чтобы пройти через него, вам нужно преобразовать его в массив, что вы можете сделать с помощью Array.prototype.slice:

var children = Array.prototype.slice.call(document.getElementById("niceParent").children);

children.forEach(…);

Ответ 3

Более чистый и современный способ преобразования HTMLCollection например .children в массив для использования forEach() (или map() и т.д.) - это использовать синтаксис распространения ... в массиве [].

var children = [...document.getElementById('x').children)];

например:

[...document.getElementById('x').children)].forEach(child => console.log(child))

Это особенность es6. Это будет работать на всех современных браузерах.

Ответ 4

Вы также можете сделать это:

NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;

И после этого вы можете вызвать forEach для вашей коллекции:

document.getElementById("niceParent").children.forEach(...)

Наилучшим и наиболее безопасным способом было бы на самом деле добавлять forEach только в тех случаях, когда он еще не существует:

if (window.NodeList && !NodeList.prototype.forEach) {
   NodeList.prototype.forEach = Array.prototype.forEach;
}
if (window.HTMLCollection && !HTMLCollection.prototype.forEach) {
   HTMLCollection.prototype.forEach = Array.prototype.forEach;
}