I would like to know what exactly is the difference between querySelector
and querySelectorAll
against getElementsByClassName
and getElementById
?
From this link I could gather that with querySelector
I can write document.querySelector(".myclass")
to get elements with class myclass
and document.querySelector("#myid")
to get element with ID myid
. But I can already do that getElementsByClassName
and getElementById
. Which one should be preferred?
Also I work in XPages where the ID is dynamically generated with colon and looks like this view:_id1:inputText1
. So when I write document.querySelector("#view:_id1:inputText1")
it doesn't work. But writing document.getElementById("view:_id1:inputText1")
works. Any ideas why?
Differences: As seen above, querySelector() methodcan only be used to access a single element while querySelectorAll() method can be used to access all elements which match with a specified CSS selector. To return all matches, querySelectorAll has to be used, while to return a single match, querySelector is used.
You should opt to use the querySelector method if you need to select elements using more complex rules that are easily represented using a CSS selector. If you want to select an element by its ID, using getElementById is a good choice.
getElementById matches the id attributes to find DOM nodes, while querySelector searches by selectors. So for an invalid selector e.g <div id="1"></div> , getElementById('1') would work while querySelector('#1') would fail, unless you tell it to match the id attribute (e.g querySelector('[id="1"]') .
getElementById() is used to access the DOM elements using their id and getElementsByClassName() is used to access element(s) using their class .
For this answer, I refer to querySelector
and querySelectorAll
as querySelector* and to getElementById
, getElementsByClassName
, getElementsByTagName
, and getElementsByName
as getElement*.
A lot of this information can be verified in the specification, a lot of it is from various benchmarks I ran when I wrote it. The spec: https://dom.spec.whatwg.org/
querySelector
and getElementById
both return a single element. querySelectorAll
and getElementsByName
both return NodeLists. The older getElementsByClassName
and getElementsByTagName
both return HTMLCollections. NodeLists and HTMLCollections are both referred to as collections of elements.These concepts are summarized in the following table.
Function | Live? | Type | Time Complexity
querySelector | | Element | O(n)
querySelectorAll | N | NodeList | O(n)
getElementById | | Element | O(1)
getElementsByClassName | Y | HTMLCollection | O(1)
getElementsByTagName | Y | HTMLCollection | O(1)
getElementsByName | Y | NodeList | O(1)
HTMLCollections are not as array-like as NodeLists and do not support .forEach(). I find the spread operator useful to work around this:
[...document.getElementsByClassName("someClass")].forEach()
Every element, and the global document
, have access to all of these functions except for getElementById
and getElementsByName
, which are only implemented on document
.
Chaining getElement* calls instead of using querySelector* will improve performance, especially on very large DOMs. Even on small DOMs and/or with very long chains, it is generally faster. However, unless you know you need the performance, the readability of querySelector* should be preferred. querySelectorAll
is often harder to rewrite, because you must select elements from the NodeList or HTMLCollection at every step. For example, the following code does not work:
document.getElementsByClassName("someClass").getElementsByTagName("div")
because you can only use getElements* on single elements, not collections. For example:
document.querySelector("#someId .someClass div")
could be written as:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
Note the use of [0]
to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with querySelector
.
Since all elements have access to both querySelector* and getElement* calls, you can make chains using both calls, which can be useful if you want some performance gain, but cannot avoid a querySelector that can not be written in terms of the getElement* calls.
Though it is generally easy to tell if a selector can be written using only getElement* calls, there is one case that may not be obvious:
document.querySelectorAll(".class1.class2")
can be rewritten as
document.getElementsByClassName("class1 class2")
Using getElement* on a static element fetched with querySelector* will result in an element that is live with respect to the static subset of the DOM copied by querySelector, but not live with respect to the full document DOM... this is where the simple live/static interpretation of elements begins to fall apart. You should probably avoid situations where you have to worry about this, but if you do, remember that querySelector* calls copy elements they find before returning references to them, but getElement* calls fetch direct references without copying.
querySelector* and getElementById
traverse elements in preorder, depth-first, called "tree order" in the specification. With other getElement* calls it is not clear to me from the specification - they may be the same as tree order, but getElementsByClassName(".someClass")[0]
may not reliably give the same result in every browser. getElementById("#someId")
should though, even if you have multiple copies of the same id on your page.
I would like to know what exactly is the difference between querySelector and querySelectorAll against getElementsByClassName and getElementById?
The syntax and the browser support.
querySelector
is more useful when you want to use more complex selectors.
e.g. All list items descended from an element that is a member of the foo class: .foo li
document.querySelector("#view:_id1:inputText1") it doesn't work. But writing document.getElementById("view:_id1:inputText1") works. Any ideas why?
The :
character has special meaning inside a selector. You have to escape it. (The selector escape character has special meaning in a JS string too, so you have to escape that too).
document.querySelector("#view\\:_id1\\:inputText1")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With