jQuery is so easy to use that sometimes we end up relying on it even for tasks that could be easily achieved using the native browser APIs. While there is nothing wrong with using jQuery, going native makes our code more portable, future proof and often more performant.
DOM selection is an example of something often performed with jQuery, but straightforward enough to achieve without any external library.
The Selectors API
The HTML5 Selectors API has been around for quite some time now, and it is supported in all modern browsers and in IE down to version 8. Its implementation is based on the
querySelector family of methods, that includes four members:
document.querySelector( selector )takes a CSS selector string and returns the first DOM element that matches the selector, or
nullif no match is found.
element.querySelector( selector )does the same, but searching only among the descendants of
document.querySelectorAll( selector )takes a CSS selector string and returns a non-live
NodeListof all the DOM elements matching the selector. If no element matches the selector, an empty list is returned.
element.querySelectorAll( selector )does the same as its counterpart defined on
document, but again searching only among the descendants of
NodeList vs. Array gotcha
It’s important to know that
querySelectorAll methods return a
NodeList, which looks similar to an array, as its elements can be accessed via their index, and it has a
length property. Unfortunately, the similarity ends there, as
NodeList does not support any of the usual array methods.
Do not try to turn a
NodeList into an array with something like
Array.prototype.slice.apply( nodeList ): although it does work in some browsers, it fails in others, as
NodeList is a host object and, as such, there is no guarantee that Array methods like
slice can be applied on it. Instead, the only reliable way to turn it into an array is to loop through all its items and populate an array:
1 2 3 4 5 6
The good news is that there seems to be no performance loss compared to the
Array.prototype.slice method. Also, as soon as ES.next will make its appearence in the browser world, we will get a very useful
Array.from method, that will turn
NodeList (and other not-quite-an-array objects like
arguments) into a proper Array in a breeze.
Building a nano-library
With these things in mind, it is trivial to build a microscopic but very efficient library for DOM selection:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
This nano-library is only about 30 lines long, but it is way more performant than jQuery or Zepto for DOM selection tasks (try benchmarking it yourself with JSPerf), and it is still very straightforward to use and legible:
1 2 3 4 5 6 7 8 9 10
The next level
A useful addition for this nano library would be a
matches method, that returns true if a selector matches an element, and false otherwise. A trivial but rather inefficient way to do this would be running a query using the selector, and then searching if the element is included in the results.
A simpler approach will soon be available with the Selectors API Level 2, using the
element.matchesSelector( selector ) method. Firefox and Chrome already provide a prefixed version of this method in their latest versions (
element.webkitMatchesSelector), and hopefully a standard implementation will come soon on all browsers.
The Selectors API Level 2 will also introduce the two methods
findAll that will be similar to
querySelectorAll, but providing also support for specifying one or more context nodes to restrict the search. With the addition of these new methods, native DOM selection will be as powerful and easy as jQuery, leaving no excuse for developers to depend on a particular framework for these kind of tasks.