Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

document.scripts is not equal to document.getElementsByTagName("script")

document.scripts returns an HTMLCollection object holding a list of all scripts in a document. Similarly, document.getElementsByTagName("script") returns another HTMLCollection object holding a list of all scripts in the document.

I expected the following statement to be true however it's not.

document.scripts === document.getElementsByTagName("script") // false

What is the reason for both these not being equal?

like image 359
coderboy Avatar asked Oct 10 '20 08:10

coderboy


People also ask

What is document getElementsByTagName?

getElementsByTagName() The getElementsByTagName method of Document interface returns an HTMLCollection of elements with the given tag name. The complete document is searched, including the root node.

Why is getElementsByTagName not working?

The "getElementsByTagName is not a function" error occurs for multiple reasons: calling the getElementsByTagName() method on a value that is not a DOM element. placing the JS script tag above the code that declares the DOM elements. misspelling getElementsByTagName (it's case sensitive).

What is the syntax of getElementsByTagName ()?

Syntax: var elements = document. getElementsByTagName(name);

How do you iterate through getElementsByTagName?

After selecting elements using the querySelectorAll() or getElementsByTagName() , you will get a collection of elements as a NodeList . To iterate over the selected elements, you can use forEach() method (supported by most modern web browsers, not IE) or just use the plain old for-loop.


2 Answers

Well, I wasn't able to find the theoretical reasoning here, but it seems that in some cases those might not be strictly equivalent, and implementations have to bear that in mind. For example, in Chromium the implementations are different, and the real funny fact is that both are cached collections:

// 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);
}

It's not just scripts: all the document HTMLCollection properties (forms, applets, images etc.) are wrapped into EnsureCachedCollection<HTMLCollection>.

For tags, however, it's EnsureCachedCollection<HTMLTagCollection>. While HTMLTagCollection is a child of TagCollection (which in turn is a child of HTMLCollection), those are different caches.

Now the way I expect caches to work, the same requests should give the same result... unless you hit different caches. In this case, same result means not just equality of values, but equivalence of objects.

That's why you get strict equivalence between both subsequent calls to document.getElementsByTagName('script') and subsequent calls to document.scripts - but not across those.

UPDATE: Check @Alohci answer, it gives a good example of when the results will actually be different by value for those requests.

like image 92
raina77ow Avatar answered Oct 24 '22 01:10

raina77ow


Here's an example where they give different results. document.scripts returns the set of HTMLElement scripts, where getElementsByTagName("script") returns the set of all scriot elements regardless of namespace.

(The StackSnippets logic adds two script elements to the document beyond those shown in the example code here.)

console.log('There are ' + document.scripts.length + ' document.scripts elements');
console.log('There are ' + document.getElementsByTagName("script").length + ' document.getElementsByTagName("script") elements');
<script>console.log('foo');</script>
<svg><script>console.log('bar');</script></svg>
like image 35
Alohci Avatar answered Oct 24 '22 02:10

Alohci