Почему jQuery не предоставляет метод .firstChild?
Я видел много дискуссий относительно самого быстрого способа выбрать первый дочерний элемент, используя jQuery. Как и следовало ожидать, собственное свойство DOM firstChild намного быстрее, чем использование селектора jQuery или комбинации селекторов - см. http://jsperf.com/jquery-first-child-selection-performance/6. Обычно это не проблема - либо она используется в месте, где производительность не имеет большого значения, либо достаточно просто получить доступ к элементу DOM и использовать его свойство .firstChild. Однако есть пара проблем с этим:
- firstChild может вернуть текст или комментарий node, а не элемент, поскольку селектор jQuery вернет
- Если мне нужно выбрать первый дочерний элемент из нескольких элементов, я должен либо использовать медленный селектор, либо перейти к много дополнительной работе, итерации по элементам DOM, добавив их в коллекцию, а затем вернув их в объект jQuery.
Мне кажется, что стоимость добавления метода firstChild в базовую библиотеку jQuery будет намного меньше преимуществ. Я попытался создать такой метод для своего использования:
$.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);
};
В тестах, которые я создал в http://jsperf.com/jquery-multiple-first-child-selection, эта функция выполняет более чем в пять раз быстрее, чем любая другая опция. Тесты основаны на тестах, упомянутых выше, но выбирают первые дети из нескольких элементов, а не один элемент.
Есть ли что-то, что мне не хватает? Техника, которую я должен использовать? Или это проблема, о которой не стоит беспокоиться? Есть ли причина не включать такую функцию в jQuery?
Ответы
Ответ 1
"Почему jQuery не предоставляет метод .firstChild?"
Ползучесть функции, скорее всего.
Это можно сделать с помощью других методов, как вы заявили, и если производительность является проблемой, вы можете расширить jQuery для этой конкретной потребности, как вы это сделали.
Вы можете улучшить производительность в коде немного больше...
$.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);
};
Ответ 2
Для случаев с одним элементом вы можете использовать
$('.test > eq(0)')
который, по-видимому, почти соответствует вашей скорости.
http://jsperf.com/jquery-multiple-first-child-selection/2