forEach não é um erro de função com a matriz JavaScript


145

Estou tentando fazer um loop simples:

const parent = this.el.parentElement
console.log(parent.children)
parent.children.forEach(child => {
  console.log(child)
})

Mas eu recebo o seguinte erro:

VM384: 53 Tipo não detectadoErro: parent.children.forEach não é uma função

Mesmo que os parent.childrenlogs:

insira a descrição da imagem aqui

Qual poderia ser o problema?

Nota: Aqui está um JSFiddle .


O mesmo problema ocorre com o element.siblings #
313 /

@Daut sim porque element.siblings retorna um HTMLCollection e HTMLCollections não tem o método foreach ()
Freddo

1
ei você, pesquisador do google! Se você está lendo esta verificação dupla, é para cada um com E maiúsculo em vez de foreach ....
Robert Sinclair

Respostas:


127

Primeira opção: invocar forEach indiretamente

O parent.childrené um objeto parecido com uma matriz. Use a seguinte solução:

const parent = this.el.parentElement;

Array.prototype.forEach.call(parent.children, child => {
  console.log(child)
});

O tipo parent.childrené NodeList, que é um objeto semelhante a uma matriz porque:

  • Ele contém a lengthpropriedade, que indica o número de nós
  • Cada nó é um valor de propriedade com nome numérico, começando em 0: {0: NodeObject, 1: NodeObject, length: 2, ...}

Veja mais detalhes neste artigo .


Segunda opção: use o protocolo iterável

parent.childrené um HTMLCollection: que implementa o protocolo iterável . Em um ambiente ES2015, você pode usar o HTMLCollectioncom qualquer construção que aceite iteráveis.

Use HTMLCollectioncom o operador spread:

const parent = this.el.parentElement;

[...parent.children].forEach(child => {
  console.log(child);
});

Ou com o for..ofciclo (que é minha opção preferida):

const parent = this.el.parentElement;

for (const child of parent.children) {
  console.log(child);
}

Quando uso sua solução, não tenho mais problemas, mas o código dentro da função anônima não é executado. .so ..
Jérémy

Qual navegador você usa para que parent.children diga que é um nodeList. No Firefox, ele diz que é uma coleção HTMLC. Se fosse um nodeList, .forEach () funcionaria #
Freddo

104

parent.childrennão é uma matriz. É HTMLCollection e não possui forEachmétodo. Você pode convertê-lo para a matriz primeiro. Por exemplo, no ES6:

Array.from(parent.children).forEach(child => {
    console.log(child)
});

ou usando o operador spread:

[...parent.children].forEach(function (child) {
    console.log(child)
});

9
Prefiro esta solução muito mais do que mexer com o protótipo Array.
Daut

E essa resposta é (uma das) respostas corretas para a pergunta dos OPs. parent.children é um HTMLCollection que não tem um método .forEach
Freddo

18

parent.childrenretornará uma lista de lista de nós , tecnicamente uma coleção html . Essa é uma matriz como objeto, mas não uma matriz, portanto, você não pode chamar funções de matriz diretamente sobre ele. Nesse contexto, você pode usar Array.from()para converter isso em uma matriz real,

Array.from(parent.children).forEach(child => {
  console.log(child)
})

Não, parent.children não retorna um nodeList, mas uma coleção HTML. Não é a mesma coisa. Se fosse um nodeList, .forEach funcionaria #
Freddo

12

Uma versão mais ingênua , pelo menos você tem certeza de que funcionará em todos os dispositivos, sem conversão e ES6:

const children = parent.children;
for (var i = 0; i < children.length; i++){
    console.log(children[i]);
}

https://jsfiddle.net/swb12kqn/5/


2
Upvoted porque todas essas novas funções ES6 fazer exatamente a mesma boa coisa velha que fosse um disponíveis, mas de um modo confuso, como sempre com JS
Freddo

8

parent.childrené um HTMLCollectionobjeto que é do tipo matriz. Primeiro, você deve convertê-lo em real Arraypara usar Array.prototypemétodos.

const parent = this.el.parentElement
console.log(parent.children)
[].slice.call(parent.children).forEach(child => {
  console.log(child)
})

2
Ou não o converta, mas use use .call () em .forEach ()?
Nnnnnn 13/03

@nnnnnn Veja minha resposta abaixo.
Dmitri Pavlutin

Existem muitas maneiras de converter um objeto parecido com um array em um array :) Esta é uma delas
Dmitriy

@DmitriyLoskutov Você não precisa convertê-lo - o JavaScript é uma linguagem de digitação de pato. Basta usar esse recurso.
Dmitri Pavlutin

5

Isso porque parent.childrené um NodeList e ele não suporta o .forEachmétodo (como NodeList é uma matriz como estrutura, mas não uma matriz), então tente chamá-lo convertendo-o primeiro em matriz usando

var children = [].slice.call(parent.children);
children.forEach(yourFunc);

Não, não é um NodeList, é uma coleção HTML
Freddo

5

Não há necessidade deforEach , você pode iterar usando apenas o fromsegundo parâmetro do seguinte modo:

let nodeList = [{0: [{'a':1,'b':2},{'c':3}]},{1:[]}]
Array.from(nodeList, child => {
  console.log(child)
});


A triste notícia é que parent.children não é um nodeList ... .from () não funcionará.
Freddo

@ Cedric se o seu objeto não for um NodeList, faça uma nova pergunta especificamente para resolvê-lo. Aqui, o downvoting é usado quando a resposta é intrinsecamente errada ou prejudicial e, como você pode ver no trecho de código, todos os elementos do objeto são iterados e impressos, que era o objetivo da pergunta do OP.
Armfoot 22/07/19

Sim, o problema é que a pergunta do OP relacionado a uma coleção HTML, não um nodeList ... Portanto, a resposta simplesmente não estava respondendo a pergunta
Freddo

@Cedric esta resposta também irá percorrer uma coleção HTML, pois Array.fromconverte o objeto fornecido no primeiro parâmetro em uma matriz. O resultado é o mesmo da resposta do madox2 sem a necessidade de um forEachloop extra ( Array.fromMDN docs).
Armfoot 24/07/19

4

Se você está tentando passar por um loop NodeListcomo este:

const allParagraphs = document.querySelectorAll("p");

Eu recomendo fazer o loop desta maneira:

Array.prototype.forEach.call(allParagraphs , function(el) {
    // Write your code here
})

Pessoalmente, eu tentei de várias maneiras, mas a maioria delas não funcionou como eu queria passar por uma NodeList, mas essa funciona como um encanto, experimente!

O NodeListnão é um array, mas o tratamos como um array, usando Array.Então, você precisa saber que ele não é suportado em navegadores mais antigos!

Precisa de mais informações NodeList? Por favor, leia sua documentação no MDN .


1
Esta resposta obviamente funciona no nodeList. O problema é retornos parent.children uma Coleção de HTML, que não é uma nodeList ...
Freddo

3

Como você está usando os recursos do ES6 ( funções de seta ), você também pode simplesmente usar um loop for como este:

for(let child of [{0: [{'a':1,'b':2},{'c':3}]},{1:[]}]) {
  console.log(child)
}


Votado. O que uma contorção, a sintaxe ES6, embora ... Me faz querer chorar, e eu estou vindo de um C ++ fundo ...
Freddo

1

Você pode verificar se digitou forEach corretamente, se digitou foreach como em outras linguagens de programação, não funcionará.


0

Você pode usar em childNodesvez de children, childNodestambém é mais confiável, considerando problemas de compatibilidade do navegador, mais informações aqui :

parent.childNodes.forEach(function (child) {
    console.log(child)
});

ou usando o operador spread:

[...parent.children].forEach(function (child) {
    console.log(child)
});
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.