为什么`forEach.call`在移除类时不遍历每个节点?

时间:2019-04-03 17:54:08

标签: javascript

我要删除assignments.created_at <=中的一个类。由于某种原因,它只调用一次,如下所示。

forEach.call
var all_active = document.getElementsByClassName("active")
Array.prototype.forEach.call(all_active, function(el) {
  el.classList.remove("active");
  console.log(el.tagName);
});

输出为<li class="active dropdown"> <a>123</a> <div class="dropdown-content"> <a class="active">1</a> <a>1</a> <a>1</a> <a>1</a> <a>1</a> <a>1</a> </div> </li>,而我希望它给出LI。为什么?

1 个答案:

答案 0 :(得分:2)

NodeList是元素的实时集合。当从第一个元素中删除类时,集合的长度也会减少。因此forEach()会得出结论,因为它已经处理了正确数量的元素。

ASCII插图可能会帮助您

 # On first iteration:      # After first iteration:
┌───────────┬──────────┐   ┌──────────┬──────────┐   
│ NodeList  │ Iterator │   │ NodeList │ Iterator │
├───────────┼──────────┤   ├──────────┼──────────┤
│ li.active │   <──    │   │ a.active │          │
├───────────┼──────────┤   ├──────────┼──────────┤
│ a.active  │          │   │          │    <─    │
└───────────┴──────────┘   └──────────┴──────────┘

第一次迭代后,li不再在集合中,因为它不再与"active"类选择器匹配。


您可以通过使用NodeListArray.from()转换为数组来避开该问题。修改节点时,数组内容不会更改,它仍将指向初始节点集。

var all_active = document.getElementsByClassName("active");

Array.from(all_active).forEach(function(el) {
  el.classList.remove("active");
  console.log(el.tagName);
});
<li class="active dropdown">
  <a>123</a>
  <div class="dropdown-content">
    <a class="active">1</a>
    <a>1</a>
    <a>1</a>
    <a>1</a>
    <a>1</a>
    <a>1</a>
  </div>
</li>