How exactly does getElementsByClassName work in Chrome?, specifically w.r.t. NodeLists & DOMs

点点圈 提交于 2019-12-12 17:04:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!