web-dev-qa-db-fra.com

Pourquoi forEach ne travaille-t-il pas pour les enfants?

J'ai un <div> Avec un enfant <div> Dedans. Par exemple.

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

J'ai essayé de les parcourir avec la fonction forEach, car je pensais que document.getElementById("niceParent").children est un tableau, car je peux accéder aux éléments avec

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]);

C'est pourquoi j'ai essayé

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

qui ne fonctionne pas. Je reçois

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

Pour contourner ce problème, je l'ai également essayé avec une boucle - beaucoup plus compliquée - 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]);
}

qui a fonctionné comme prévu.

Pourquoi?

31
erik

Car .children contient un NodeList[MDN] , pas un tableau. Un objet NodeList est un objet semblable à un tableau, qui expose un .length propriété et possède des propriétés numériques, juste comme tableaux, mais il n'hérite pas de Array.prototype et n'est donc pas un tableau.

Vous pouvez le convertir en tableau à l'aide de Array.prototype.slice:

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

ECMAScript 6 introduit une nouvelle API pour convertir les itérateurs et les objets de type tableau en tableaux réels: Array.from[MDN] . Utilisez-le si possible car cela rend l'intention beaucoup plus claire.

var children = Array.from(document.getElementById(...).children);
49
Felix Kling

Element.children n'est pas pas un tableau. Il s'agit d'un objet appelé HTMLCollection. Celles-ci n'ont pas de méthodes de tableau (bien qu'elles aient la propriété length).

Pour le parcourir, vous devrez le convertir en un tableau, ce que vous pouvez faire en utilisant Array.prototype.slice :

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

children.forEach(…);
10
lonesomeday

Une façon plus propre et plus moderne de convertir un HTMLCollection comme .children En un tableau pour utiliser forEach() (ou map(), etc.) consiste à utiliser le propagation synthax ... dans un tableau [].

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

par exemple:

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

Il s'agit d'une fonctionnalité es6. Cela fonctionnera sur tous les navigateurs modernes.

3
aloisdg

Vous pouvez également le faire:

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

Et après cela, vous pouvez appeler forEach sur votre collection:

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

Le meilleur moyen et le plus sûr serait en fait d'ajouter seulement forEach dans les cas où il n'existe pas déjà:

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