Javascript 使用node.childNodes.forEach删除childNodes
传统上,在Javascript中删除节点子节点的建议方法是执行以下操作:Javascript 使用node.childNodes.forEach删除childNodes,javascript,dom,ecmascript-6,nodelist,Javascript,Dom,Ecmascript 6,Nodelist,传统上,在Javascript中删除节点子节点的建议方法是执行以下操作: while(node.firstChild) { node.removeChild(node.firstChild); } 最近,我尝试使用内置的forEach()方法删除节点的所有子节点: 这并没有像我预期的那样起作用。forEach不再删除所有子节点,而是停止执行,留下剩余节点。最后我不得不使用Array.from: Array.from(node.childNodes) 然后我可以用forEach删除节点
while(node.firstChild) {
node.removeChild(node.firstChild);
}
最近,我尝试使用内置的forEach()方法删除节点的所有子节点:
这并没有像我预期的那样起作用。forEach不再删除所有子节点,而是停止执行,留下剩余节点。最后我不得不使用Array.from:
Array.from(node.childNodes)
然后我可以用forEach删除节点。我之所以不能使用上面提到的传统方法,是因为出于某种原因,总是有一个孩子落在后面,造成了一个无限循环
为什么childNodes.forEach方法不像我想象的那样删除所有节点?我误解了什么?
node.childNodes
是一个实时集合。当您从集合中删除项时,集合本身将被修改(在迭代时处于活动状态)。尝试按原样对其进行迭代会导致元素从集合中删除,并在迭代时在类似数组的结构中向下移动,从而导致丢失节点
例如,当对集合中的第二个元素调用removeChild()
时,该元素本身将从集合中移除。这将导致第三个元素移动到集合中第二个元素所在的位置。现在,循环移动到集合中的第三个元素。但是,这将跳过现在位于第二位置的元素,导致您永远无法删除它
这意味着遍历实际集合并删除内容的唯一安全方法是向后遍历,因为从末尾删除内容不会导致其他元素更改其在集合中的位置。从前面移除项目(这是您正在做的)会导致项目在集合中移动
Array.from()
将live集合转换为静态数组,从DOM中删除项时不会从数组中删除项
我有一个DOM开发的个人规则,即在我以任何方式修改DOM时,永远不要使用live collection,因为在我尝试使用它时,live collection被修改的危险太大了Array.from()
是一种非常简单的方法,可以获取动态集合的副本,该副本是静态的,即使在修改DOM时也可以安全使用
另一种安全的删除方法是使用此向后迭代,因为项目将从live collection的末尾删除,这不会导致任何项目在您尚未处理的集合中移动:
for (let i = node.childNodes.length - 1; i >= 0; i--) {
node.removeChild(node.childNodes[i]);
}
但是,我通常觉得这比您已经发现的使用
array.from()
转换为静态数组更麻烦。node.childNodes
是一个实时集合。当您从集合中删除项时,集合本身将被修改(在迭代时处于活动状态)。尝试按原样对其进行迭代会导致元素从集合中删除,并在迭代时在类似数组的结构中向下移动,从而导致丢失节点
例如,当对集合中的第二个元素调用removeChild()
时,该元素本身将从集合中移除。这将导致第三个元素移动到集合中第二个元素所在的位置。现在,循环移动到集合中的第三个元素。但是,这将跳过现在位于第二位置的元素,导致您永远无法删除它
这意味着遍历实际集合并删除内容的唯一安全方法是向后遍历,因为从末尾删除内容不会导致其他元素更改其在集合中的位置。从前面移除项目(这是您正在做的)会导致项目在集合中移动
Array.from()
将live集合转换为静态数组,从DOM中删除项时不会从数组中删除项
我有一个DOM开发的个人规则,即在我以任何方式修改DOM时,永远不要使用live collection,因为在我尝试使用它时,live collection被修改的危险太大了Array.from()
是一种非常简单的方法,可以获取动态集合的副本,该副本是静态的,即使在修改DOM时也可以安全使用
另一种安全的删除方法是使用此向后迭代,因为项目将从live collection的末尾删除,这不会导致任何项目在您尚未处理的集合中移动:
for (let i = node.childNodes.length - 1; i >= 0; i--) {
node.removeChild(node.childNodes[i]);
}
但是,我通常认为这比您已经发现的使用
array.from()
转换为静态数组更麻烦。node.childNodes
是一个活动的集合,因此当您从forEach中的node
移除子节点时,您会弄乱迭代器
node.childNodes
是一个活动的集合,因此当您从forEach中的node
中删除子节点时,您会弄乱迭代器
您看到结果中的模式了吗?想想在每次迭代中节点列表会发生什么。术语“内置”指的是ECMAScript的特性,主机提供的任何东西都是主机方法。因此节点列表实例的forEach方法不是“内置的”,而是一个宿主方法你看到结果中的模式了吗?想想在每次迭代中节点列表会发生什么。术语“内置”指的是ECMAScript的特性,主机提供的任何东西都是主机方法。因此节点列表实例的forEach方法不是“内置的”,而是一个宿主方法我明白了,谢谢你花时间解释。@m.chiang-DOM的设计师们到底拥有什么,甚至可以为我们提供现场收藏,这对我来说是个谜。它们造成的麻烦比我想象的任何公用事业都要多。幸运的是,
queryselectoral()