document.scripts 不等于 document.getElementsByTagName("script")

cod*_*boy 6 html javascript dom htmlcollection

document.scripts返回一个HTMLCollection包含文档中所有脚本列表的对象。同样,document.getElementsByTagName("script")返回另一个HTMLCollection对象,其中包含文档中所有脚本的列表。

我预计以下陈述是正确的,但事实并非如此。

document.scripts === document.getElementsByTagName("script") // false
Run Code Online (Sandbox Code Playgroud)

这两者不相等的原因是什么?

rai*_*7ow 5

好吧,我在这里找不到理论推理,但似乎在某些情况下这些可能并不严格等效,并且实现必须牢记这一点。例如,在 Chromium 中,实现是不同的,真正有趣的事实是两者都是缓存集合:

// renderer/core/dom/document.cc
HTMLCollection* Document::scripts() {
  return EnsureCachedCollection<HTMLCollection>(kDocScripts);
}

// renderer/core/dom/container_node.cc
HTMLCollection* ContainerNode::getElementsByTagName(
    const AtomicString& qualified_name) {
  DCHECK(!qualified_name.IsNull());

  if (GetDocument().IsHTMLDocument()) {
    return EnsureCachedCollection<HTMLTagCollection>(kHTMLTagCollectionType,
                                                     qualified_name);
  }
  return EnsureCachedCollection<TagCollection>(kTagCollectionType,
                                               qualified_name);
}
Run Code Online (Sandbox Code Playgroud)

这不仅仅是scripts:所有文档 HTMLCollection 属性(表单、小程序、图像等)都被包装到EnsureCachedCollection<HTMLCollection>.

然而,对于标签来说,它是EnsureCachedCollection<HTMLTagCollection>. 虽然 HTMLTagCollection 是 TagCollection 的子级(TagCollection 又是 HTMLCollection 的子级),但它们是不同的缓存。

现在,按照我期望缓存的工作方式,相同的请求应该给出相同的结果......除非您命中不同的缓存。在这种情况下,相同的结果不仅意味着值相等,还意味着对象相等。

这就是为什么您在后续调用document.getElementsByTagName('script')和后续调用之间获得严格等价document.scripts- 但不能跨这些调用。

更新:检查@Alohci 答案,它给出了一个很好的例子,说明这些请求的结果实际上何时会有所不同。


Alo*_*hci 4

这是一个给出不同结果的示例。document.scripts 返回HTMLElement脚本集,其中 getElementsByTagName("script") 返回所有 scriot 元素的集,无论命名空间如何。

(StackSnippets 逻辑向文档添加了两个脚本元素,超出了此处示例代码中显示的元素。)

console.log('There are ' + document.scripts.length + ' document.scripts elements');
console.log('There are ' + document.getElementsByTagName("script").length + ' document.getElementsByTagName("script") elements');
Run Code Online (Sandbox Code Playgroud)
<script>console.log('foo');</script>
<svg><script>console.log('bar');</script></svg>
Run Code Online (Sandbox Code Playgroud)