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 .

alexchenco
fonte
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);
}
Dmitri Pavlutin
fonte
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)
});
madox2
fonte
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)
})
Rajaprabhu Aravindasamy
fonte
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/

Jean
fonte
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)
})
Dmitriy
fonte
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);
Ammar Hasan
fonte
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)
});

Armfoot
fonte
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 .

Elharony
fonte
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)
}

Armfoot
fonte
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á.

Abdelsalam Megahed
fonte
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)
});
Syed
fonte