Does the e.matches() method have to traverse the DOM to evaluate the selector?
I ask because of a situation such as:
if ( e.matches('.class_1, .class_1 *') {
/* Do something. */
} else if ( e.matches('.class_2, .class_2 *') {
/* Do something. */
} else if ( e.matches('.class_3, .class_3 *') {
/* Do something. */
} else {
/* Do something. */
}
If the DOM is traversed from the element e
up the ancestor tree to determine if e.matches() is true/false; then it would repeat the process for each else if
when the previous condition is false. So, I wondered if this was not inefficient and I should just loop up the ancestor tree once using e.classList.contains()
to find which of the set (class_1, class_2, class_3) is encountered first or reach an ancestor element that indicates that should stop searching. But contains()
doesn’t appear to be a quick test either.
let c = e.classList;
while ( e ) {
if ( c.contains('class_1') ) {
/* Do something. */
break;
} else if ( c.contains('class_2') ) {
/* Do something. */
break;
} else if ( c.contains('class_3') ) {
/* Do something. */
break;
}
e = e.parentNode;
}
In this DOM sturcture class_1 is always deeper down than class_2 which is always deeper down than class_3. So, I’d like to determine to which level e
belongs first. Which element is the class_1, 2, 3 does not need to be determined, but only to which of them (if any) e
is closest to on the way up the tree.
Thank you.
3
Answers
It probably has to traverse the ancestor list so there might be some waste, but traversing it yourself once might not be faster than the browser traversing it 3 times.
If the site has a noticable performance issue (e.g. if this operation is performed a lot of times), you can measure both methods on different browsers and see what’s faster. But in most cases there wouls be practically no difference anyway and then it’s probably better to go with what makes the code clearer.
You could do the "heavy" work outside any of the loops by analysing the classes that have been assigned to the clicked (or otherwise selected) element:
Seeing that your sequence of
if
statements always filters out the alphabetically lowest "class_…" entry you can simplify the script further to:If I understand the question correctly, it seems that you want the element method
closest()
using a selector list of your class names: