使用 node.childNodes.forEach 移除子节点

removing childNodes using node.childNodes.forEach

传统上,在 Javascript 中删除节点的 children 的建议方法是执行以下操作:

while(node.firstChild) {
    node.removeChild(node.firstChild);
}

最近,我尝试使用内置的 forEach() 方法删除节点的所有 children:

node.childNodes.forEach(child => {
    node.removeChild(child);
}

这没有按我的预期运行。 forEach 没有删除所有 child 节点,而是停止执行,留下剩余节点。我最终要做的是使用 Array.from:

Array.from(node.childNodes)

然后我可以使用 forEach 删除节点。之所以不能使用上面提到的传统方法是因为某些原因,总是留下一个child,造成死循环。

为什么 childNodes.forEach 方法没有像我想的那样删除所有节点?我误会了什么?

node.childNodes为现场合集。当您从中删除项目时,集合本身会被修改(在您迭代时处于活动状态)。尝试按原样对其进行迭代,会导致元素从集合中移除并在迭代时在类似数组的结构中向下移动,从而导致您错过节点。

例如,当您对集合中的第二个元素调用 removeChild() 时,该元素本身将从集合中删除。这导致第三个元素被移动到集合中第二个元素所在的位置。现在,您的循环移动到集合中的第三个元素。但是,这将跳过现在位于第二个位置的元素,导致您永远无法删除它。

这意味着迭代实际集合并删除内容的唯一安全方法是向后遍历,因为从末尾删除内容不会导致其他元素改变它们在集合中的位置。从前面移除项目(这是你正在做的)确实会导致项目在集合中移动。

Array.from() 将实时集合转换为静态数组,其中在从 DOM.

中删除项目时不会从数组中删除项目

我有一个 DOM 开发的个人规则,在我以任何方式修改 DOM 时永远不要使用实时集合,因为实时集合在我修改时被修改的危险试图使用它太高了。 Array.from() 是获取动态集合副本的一种非常简单的方法,它是静态的并且可以安全使用,即使 DOM 正在被修改。


另一种将它们全部删除的安全方法是使用这种向后迭代,因为项目是从实时集合的末尾删除的,这不会导致任何项目在您尚未处理的集合中移动:

for (let i = node.childNodes.length - 1; i >= 0; i--) {
   node.removeChild(node.childNodes[i]);
}

但是,我通常发现这比您已经发现的仅使用 Array.from() 转换为静态数组更麻烦。

node.childNodes 是一个 实时集合 ,因此当您从 forEach 中的 node 中删除子项时,您会弄乱迭代器。

https://developer.mozilla.org/en-US/docs/Web/API/Node/childNodes