Подтвердить что ты не робот

Как оценивается селектор jQuery $('# foo a')?

В качестве примера кода jQuery (https://coderwall.com/p/7uchvg) я прочитал, что выражение $('#foo a'); ведет себя следующим образом:

Найдите каждый a на странице, а затем отфильтруйте a внутри #foo.

И это выглядит неэффективно.

Это правильно? И если да, то как нам это сделать лучше?

4b9b3361

Ответ 1

Это правильно - Sizzle (механизм выбора jQuery) ведет себя так же, как и селектор CSS. Селекторы CSS и Sizzle оцениваются справа налево, и поэтому #foo a найдет все узлы a, а затем отфильтровывает те узлы, которые спускаются с #foo.

Вы улучшаете это, гарантируя, что ваши селекторы листьев имеют высокую специфичность, обычно, предоставляя им класс или идентификатор.

Ответ 2

как нам это сделать лучше?

Используйте параметр контекста из jQuery.

$('a', '#foo');

Теперь jQuery будет искать все якоря в контексте элемента с id: foo.

В вашем запросе контекст по умолчанию считается документом при пропуске:

$('#foo a'); == $('#foo a', document); 

В этом случае ваш запрос действительно неэффективен.

Вы можете посмотреть в этой статье.

Ответ 3

Хотя верно, что Sizzle является движком справа налево (это то же самое, что интерпретируется css), неверно, что конкретный селектор в вашем примере будет выбирать все элементы привязки на странице, а затем фильтровать их родители соответствуют идентификатору "foo". Sizzle фактически оптимизирует любой селектор, который начинается с идентификатора, и использует его как контекст для всего выделения, а не для использования документа. Другими словами, выбранный вами селектор в основном переводится на:

document.getElementById("foo").getElementsByTagName("a")

Действительно, это не плохой селектор вообще.

Однако, учитывая другие вещи, которые должен выполнить jQuery (который включает в себя цикл над элементами для их объединения на экземпляр jQuery), jQuery ( "# foo" ). find ( "a" ) всегда будет самым быстрым, поскольку jQuery реализует ярлык создания объекта jQuery для селекторов только для идентификаторов, а затем он находит корневой путь из #foo.

Другими словами, сам Sizzle не сильно отличается при выполнении Sizzle("#foo a") и Sizzle("a", document.getElementById("foo")), но jQuery("#foo").find... будет быстрее из-за ярлыка собственного идентификатора jQuery.

Кстати, мои замечания о Sizzle предполагают, что querySelectorAll не используется. Если это так, Sizzle просто передает его на qsa, что все еще не так быстро, как использование ярлыка ID jQuery.

Ответ 4

Вы можете использовать функцию find() для более детального контроля над порядком выбора:

$('#foo').find('a');

Это, конечно, будет более впечатляющим с более сложными селекторами, где вы можете цепью find() и filter().

Для записи $('#foo').find('a') === $('a','#foo')

[Update] ok, позже я понял, что это именно то, что говорит ваша ссылка...

Механизм селектора jQuery (Sizzle) был реорганизован в прошлом году, здесь вы найдете подробные объяснения: http://www.wordsbyf.at/2011/11/23/selectors-selectoring/

Ответ 5

Вместо фильтрации с помощью a внутри элементов #foo просто присоедините класс к элементам a и получите элементы a с классом типа $("a.class");. Это было бы более эффективно.

Ответ 6

Еще один "попробуй это для себя":

Похоже, что это не так сильно отличается от "плоской" DOM (1 и 2), но производительность значительно отличается от вложенной DOM.

Также обратите внимание, что некоторые из тестовых примеров не выбирают правильные элементы (т.е. $('.a') vs $('.a', context)), но я оставил их из исходных тестов только для сравнения.

Ответ 7

В этом примере будут извлекаться все элементы привязок a в элементе с именем foo, чтобы найти все a на странице, а затем отфильтровать внутри #foo, как вы хотите, и вы должны выбрать a #foo

$("a #foo");

это приведет к извлечению всех элементов foo внутри элементов a.