I have seen plenty of discussion regarding the fastest way to select a first child element using jQuery. As can be expected, the native DOM firstChild property is much faster than using a jQuery selector or combination of selectors -- see http://jsperf.com/jquery-first-child-selection-performance/6. This is not usually a problem -- either it's being used in a place where performance is not a big deal, or it's easy enough to just access the DOM element and use its .firstChild property. However, there are a couple problems with this:
It seems to me that the cost of adding a firstChild method to the core jQuery library would be far smaller than the benefits. I took my own shot at creating such a method for my own use:
$.fn.firstChild = function() {
var ret = [];
this.each(function() {
var el = this.firstChild;
//the DOM firstChild property could return a text node or comment instead of an element
while (el && el.nodeType != 1)
el = el.nextSibling;
if (el) ret.push(el);
});
//maintain jQuery chaining and end() functionality
return this.pushStack(ret);
};
In the tests I created at http://jsperf.com/jquery-multiple-first-child-selection, this function performs more than five times faster than any other option. The tests are based on the tests mentioned above, but are selecting the first children of multiple elements, rather than a single element.
Is there something I am missing? A technique that I should be using? Or is this an issue than one should never worry about? Is there a reason to not include a function like this in jQuery?
"Why does jQuery not provide a .firstChild method?"
Feature creep, most likely.
It can be accomplished with other methods as you stated, and if performance is a concern, you can extend jQuery for that specific need as you've done.
You can improve performance in your code a little more...
$.fn.firstChild = function () {
var ret = [];
// use a for loop
for (var i = 0, len = this.length; i < len; i++) {
var this_el = this[i],
el = this_el.firstElementChild; // try firstElementChild first
if (!el) {
el = this_el.firstChild;
while (el && el.nodeType != 1)
el = el.nextSibling;
}
if (el) ret.push(el);
}
//maintain jQuery chaining and end() functionality
return this.pushStack(ret);
};
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