forEach不是JavaScript数组的函数错误


145

我试图做一个简单的循环:

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

但我收到以下错误:

VM384:53未捕获的TypeError:parent.children.forEach不是一个函数

即使parent.children日志:

在此处输入图片说明

可能是什么问题呢?

注意:这是一个JSFiddle


element.siblings发生相同的问题
Daut

@Daut是,因为element.siblings返回一个HTMLCollection,而HTMLCollections没有forEach()方法
Freddo

1
嗨,谷歌搜索者!如果您正在阅读此双重检查,它是forEach用大写字母E代替foreach ....
罗伯特·辛克莱尔

Answers:


127

第一种选择:间接调用forEach

parent.children是像对象的数组。使用以下解决方案:

const parent = this.el.parentElement;

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

parent.childrenIS NodeList类型,就像对象,因为数组:

  • 它包含 length属性,该属性指示节点数
  • 每个节点都是一个具有数字名称的属性值,从0开始: {0: NodeObject, 1: NodeObject, length: 2, ...}

请参阅本文的更多详细信息。


第二种选择:使用可迭代协议

parent.children是一个HTMLCollection:实现可迭代协议。在ES2015环境中,您可以将HTMLCollection搭配任何接受迭代的构造一起使用。

使用HTMLCollection与传播operatator:

const parent = this.el.parentElement;

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

或使用for..of循环(这是我的首选):

const parent = this.el.parentElement;

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

当我使用您的解决方案时,我再也没有问题了,但是匿名函数内部的代码没有执行。。所以..
杰里米

您使用哪个浏览器,以便parent.children告诉您它是一个nodeList。在Firefox上,它告诉我是HTMLCollection。如果它是一个nodeList,则.forEach()将起作用
Freddo

104

parent.children不是数组。它是HTMLCollection,没有forEach方法。您可以先将其转换为数组。例如在ES6中:

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

或使用传播运算符:

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

9
我更喜欢这种解决方案,而不是弄乱Array原型。
Daut

这个答案是OP问题的正确答案之一。parent.children是不具有一个.forEach方法的HTMLCollection
Freddo

18

parent.children将返回节点列表列表,从技术上讲是html Collection。那是一个类似于对象的数组,而不是一个数组,因此您不能直接在其上调用数组函数。在这种情况下,您可以Array.from()用来将其转换为真实数组,

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

不,parent.children不返回nodeList而是返回HTML集合。不一样的东西。如果它是一个nodeList,那么.forEach将起作用
Freddo

12

一个更幼稚的版本,至少您确定它可以在所有设备上运行,而无需转换和ES6:

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

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


2
Upvoted因为所有这些新功能ES6做正是是一个提供同样良好的老东西,但在一个混乱的方式,一如既往地与JS
Freddo

8

parent.children是一个HTMLCollection类似于数组的对象。首先,您必须将其转换为实际Array使用Array.prototype方法。

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

2
还是不进行转换,而是在.forEach()上使用use .call()?
nnnnnn

@nnnnnn请参阅下面的答案。
Dmitri Pavlutin

有很多方法可以将类似数组的对象转换为数组:)这就是其中之一
Dmitriy

@DmitriyLoskutov您无需对其进行转换-JavaScript是一种鸭子输入语言。只需使用此功能。
Dmitri Pavlutin

5

那是因为它parent.children是一个NodeList,并且它不支持该.forEach方法(因为NodeList是一个类似于结构的数组,但不是数组),因此请尝试通过首先使用将其转换为array来调用它

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

不,它不是NodeList,而是HTML集合
Freddo

5

没有必要的forEach,你可以遍历仅使用from的第二个参数,如下所示:

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


不幸的是,parent.children不是nodeList ... .from()无法正常工作。
弗雷多(Freddo)

@Cedric如果您的对象不是NodeList,则应该提出一个专门解决它的新问题。在这里,当答案本质上是错误的或有害的时(如您从代码片段中看到的那样),将使用下降投票,这是对象的所有元素被迭代和打印的问题,这是OP的目标。
Armfoot

是的,问题在于OP的问题与HTML集合有关,而不是与nodeList有关...因此答案仅仅是没有回答问题
Freddo

@Cedric此答案还将遍历HTML集合,因为它将Array.from第一个参数中给出的对象转换为数组。结果与madox2的答案相同,而无需额外的forEach循环(Array.fromMDN文档)。
Armfoot

4

如果您试图NodeList像这样循环播放:

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

我强烈建议这样循环:

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

就个人而言,我尝试了几种方法,但是大多数方法都无法正常工作,因为我想循环 NodeList,但是这种方法就像一种魅力,请尝试一下!

NodeList不是数组,但是我们使用Array.所以,你需要知道它是不是在旧的浏览器的支持!

需要有关的更多信息NodeList?请阅读其有关MDN的文档


1
这个答案显然适用于nodeList。麻烦的是parent.children返回的HTML集合不是nodeList ...
Freddo

3

由于您正在使用ES6的功能箭头功能),因此您也可以仅使用如下所示的for循环

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


已投票。但是,ES6语法是一种扭曲,但是……让我想哭了,而我来自C ++背景……
Freddo


0

考虑到浏览器兼容性问题,您可以使用childNodes代替childrenchildNodes也更加可靠,有关更多信息,请参见

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

或使用传播运算符:

[...parent.children].forEach(function (child) {
    console.log(child)
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.