【问题标题】:Why do Array.prototype.slice.call(nodeList) for DOM elements?为什么 Array.prototype.slice.call(nodeList) 用于 DOM 元素?
【发布时间】:2012-11-08 18:26:45
【问题描述】:

许多 JavaScript 库(jQuery、Zepto)似乎在 querySelectorAll()、getElementsByTag 或 ClassName 结果上调用 Array.prototype.slice.call...

通过阅读 StackOverflow 上的许多类似问题/答案,我确实了解它将 NodeList 结果转换为真正的 Array,以便您可以对 NodeLists 上不可用的结果调用 Array 方法(切片、弹出) - 但是我不明白为什么?您通常不需要在 DOM 节点列表上进行切片/弹出操作 + NodeLists 已经具有长度属性,因此无论如何它们都是可遍历的。

一些答案​​似乎暗示这是因为 NodeList 指向活动的 DOM 对象。但是如果你把它转换成一个数组,引用仍然指向活动的 DOM 节点——那么有什么区别呢?

或者是我完全想念的其他东西?它是否有助于 Zepto/jQuery 以某种方式缓存 DOM 元素的多个属性调用? (虽然我真的不明白,因为这些仍然是实时 DOM 引用)

【问题讨论】:

  • NodeList 指向活动 DOM 对象是对的,但这意味着当一个对象被销毁(或不再是列表的有效项目)时,它和它的位置是从列表中删除。当您切入一个数组时,它不是同一个“活动”列表 - 元素本身是活动的,但不是列表本身。当一个项目被销毁时,它的位置仍然保留在数组中......但它不会代表元素 - 我猜它会变得未定义或为空。
  • @Ian 如果数组包含对 DOM 节点的引用,则该节点不能被垃圾回收。
  • @Alnitak 我明白了,那么我猜我的评论会变成类似“,它的位置仍然保留在数组中并且元素保留,直到不再引用它。 ..那么数组中的值将是未定义的或空的”。对吗?
  • @Ian 不,这不正确,因为元素 不能 有“没有更多引用”,因为 数组中还有一个! .避免这种情况的唯一方法是显式将数组元素设置为其他元素,以便数组不再持有该引用,
  • 啊我明白了 - 是的,谢谢,这当然是一个合理的解释......虽然 - 这不是一件坏事吗?我的意思是,这意味着转换后的数组仍将保留对可能已被删除的 DOM 元素的引用 - 从而将其标记为“仍在使用”并向垃圾收集器发出不应从内存中删除的信号?

标签: javascript arrays nodelist


【解决方案1】:

您通常不需要在 DOM 节点列表上进行切片/弹出

实际上,你这样做了,这正是它的必要性。

例如,.eq().first() 等如何工作。 jQuery 对象在数组中包含NodeList副本,然后各个方法获取该数组的切片。同样,您不能将.add() 节点转换为NodeList

此外,即使其中的元素随后从 DOM 中删除,这些数组也需要保持有效。数组中的引用仍然有效,可用于将这些元素重新插入 DOM。

如果您拥有的只是一个实时的NodeList,那么当它们从 DOM 中移除时,这些元素会自动从列表中消失,并且会永远丢失,除非您对它们有单独的引用。

【讨论】:

  • @TinyGiant some NodeList 对象是活动的,有些是静态的。 querySelectorAll 返回的那个是静态的。建议您阅读有关上述问题的大量评论线程。
  • 请注意,如果 nodeList 是 SVG 元素,则 Array.prototype.slice.call(nodeList) 不适用于某些 IE 版本
【解决方案2】:

...因为 NodeList 指向活动的 DOM 对象...

不,这是个误会。关键不是列表中的每个节点都是“活动的”DOM 对象(真实但不相关),而是 列表本身 是“活动的”。换句话说,只要 DOM 发生更改,列表的内容就可能随时更改(甚至增长或缩小)。

如果您对列表中的项目执行更改 DOM 的操作,则列表本身可能会在您使用它时即时更改。这意味着您的代码在幕后可能会遇到非常奇怪的递归和/或性能问题,而您却没有意识到这一点,而且源代码中几乎没有任何迹象。

将 NodeList 转换为常规的 Javascript 数组会消除列表本身的这种“活跃性”,从而消除了自取其辱的机会。

【讨论】:

  • @TinyGiant 有些肯定是,例如aNode.childNodes。您的示例使用了querySelectorAll,它返回一个非活动的 NodeList。
猜你喜欢
  • 1970-01-01
  • 2016-10-17
  • 2010-11-10
  • 2013-10-06
  • 2011-07-05
  • 1970-01-01
  • 2019-12-14
  • 2021-06-18
  • 1970-01-01
相关资源
最近更新 更多