问题
All of the following results were obtained using Google Chrome v36 & its console.
While debugging a Wordpress plugin, I discovered that running this little Javascript snippet
console.log(document.getElementsByClassName("switch-tmce"))
console.log(document.getElementsByClassName("switch-tmce").length)
would log the following (expanded after the page finished loading):
[item: function, namedItem: function]
0: a#ninja_forms_field_10-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
1: a#ninja_forms_field_15-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
length: 2
ninja_forms_field_10-tmce: a#ninja_forms_field_10-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
ninja_forms_field_15-tmce: a#ninja_forms_field_15-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
__proto__: HTMLCollection
0
If I adjusted the snippet to wait for the DOM to finish loading like so:
window.addEventListener("DOMContentLoaded", function() {
console.log(document.getElementsByClassName("switch-tmce"))
console.log(document.getElementsByClassName("switch-tmce").length)
}, false);
it would then log the following (expanded after the page finished loading):
[a#ninja_forms_field_10-tmce.hide-if-no-js.wp-switch-editor.switch-tmce, a#ninja_forms_field_15-tmce.hide-if-no-js.wp-switch-editor.switch-tmce, ninja_forms_field_10-tmce: a#ninja_forms_field_10-tmce.hide-if-no-js.wp-switch-editor.switch-tmce, ninja_forms_field_15-tmce: a#ninja_forms_field_15-tmce.hide-if-no-js.wp-switch-editor.switch-tmce, item: function, namedItem: function]
0: a#ninja_forms_field_10-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
1: a#ninja_forms_field_15-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
length: 2
ninja_forms_field_10-tmce: a#ninja_forms_field_10-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
ninja_forms_field_15-tmce: a#ninja_forms_field_15-tmce.hide-if-no-js.wp-switch-editor.switch-tmce
__proto__: HTMLCollection
2
What I'm having trouble understanding is just what exactly is happening here - in particular, why the length
property only returns "correctly", so to speak, after the DOM loads. I've found this explanation:
It might be, that while calling getElementsByTagName, no input elements exist, but since NodeLists are dynamic, when the document loads, elements will contain all 28 inputs.
but I'm reading that as saying that getElementsByTagName parses the NodeList until it can parse the DOM, and can only return the length
property when parsing the DOM, which doesn't seem right to me, since it still has finite countable elements.
Moreover, there's also the matter of [item:function, namedItem:function]
changing to [a.someClass.someOtherClass, a.someclass.someOtherClass]
, which the above doesn't explain.
Hence my question: What exactly is happening under the hood with getElementsByClassName
that the length
property is not set (does not exist?) until after the DOM loads, despite that the prototype remains the same? How is this related to/why does the output change from [item:function, namedItem:function]
to [a.someClass.someOtherClass, a.someclass.someOtherClass]
?
回答1:
As you can see, getElementsByClassName
returns a HTMLCollection
- that is, a live reference for your query.
What's happening is that you're expanding the live reference in the console after the DOM is ready, but logging it before the DOM is ready. Because it is a live reference, by expanding when the DOM is ready, when the HTMLCollection
references the object in the memory, it sees that the DOM is ready and pulls from the finished DOM.
If, however, you expanded the reference while having paused the execution of the Javascript (this can be done with something like debugger
), this is what you would get:
[item: function, namedItem: function]
length: 0
__proto__: HTMLCollection
0
because the DOM would not yet be ready then.
That's why the first logged reference showed up as [item: function, namedItem: function]
, because when you logged it, the DOM wasn't ready. Once the DOM was ready, it was logged as [a.someClass.someOtherClass, a.someClass.someOtherClass]
.
The length output, though, is just a number, not an object reference, and logs as is, which is why it prints 0 before the DOM is ready and 2 after it is - because that's exactly what's happening, since there are no DOM elements before the DOM is ready.
回答2:
Nodelist is a superset to HTMLcollection. Specifically Nodelist is the constructor which makes HTMLcollection.
var list = document.getElementsByClassName("classname");
console.log(list)
Now you will see :
__proto__ : NodeList();
console.log(NodeList) //-> function NodeList()
So a HTMLcollection is just a nodeList that contains elements and not text. (Nodelist's can contain text) to form a nodelist you must use the methods: Node.childNodes Element.classList
and probably some recursion to build it.
来源:https://stackoverflow.com/questions/25276315/how-exactly-does-getelementsbyclassname-work-in-chrome-specifically-w-r-t-nod