jQuery для начинающих
BlogGitHub
  • jQuery для начинающих
  • Об авторе
  • О книге
  • Условия распространения
  • 0% Об HTML, CSS и JavaScript
    • Семантическая вёрстка
    • Валидный HTML
    • CSS-правила и селекторы
    • CSS. Погружение
    • Разделяй и властвуй
    • Немного о JavaScript
  • 10% Подключаем, находим, готовим
    • Будь готов!
    • Селекторы
    • Селекторы и Sizzle
    • Оптимизация
  • 20% Атрибуты и свойства элементов
    • CSS стили
    • CSS классы
    • Атрибуты
    • Свойства
    • Размеры
    • Позиция
    • Data-атрибуты
  • 30% События
    • Работа с событиями
    • Всплытие и обработка событий
    • Пространство имен
    • «Живые» события
    • Touch-события
    • Оптимизация
    • Дополнение
  • 40% Анимация
    • Easing функции
    • Прогресс
    • Шаг за шагом
    • В очередь…©
    • Отключение
  • 50% Манипуляции с DOM
    • Создание элементов
    • Манипуляции над элементами
    • Управление содержимым
    • Клонирование и удаление
    • Полоса прокрутки
  • 60% AJAX
    • Метод load()
    • Метод ajax()
    • Обработчики событий
    • Лечим JavaScript-зависимость
    • Сила JSONP
    • Прокачиваем AJAX
  • 70% Ассинхронность
    • Deferred
    • When
    • Callbacks
  • 80% Работа с формами
    • События
    • Манипуляциия над элементами
  • 90% Пишем свой плагин
    • Первый плагин
    • Data реестр
    • Animate
    • Easing
    • Sizzle
  • 100% Последняя глава
  • Дополнение
    • jQuery UI
      • Пишем свой widget
    • jQWidgets
    • Ещё плагины
    • Обновление на версию 2.х
    • Обновление на версию 3.х
    • Обновление на версию 4.х
  • История изменений
  • Благодарности
Powered by GitBook
On this page
  1. 10% Подключаем, находим, готовим

Селекторы и Sizzle

PreviousСелекторыNextОптимизация

Last updated 1 year ago

Пропустите это раздел, и вернитесь к нему тогда, когда вас заинтересует, как происходит поиск элементов внутри $(...)

В качестве «поисковика» по элементам DOM jQuery использует библиотеку . Данная библиотека одно время была неотъемлемой частью jQuery, затем «отпочковалась» в отдельный проект, который с радостью используется как самим jQuery, так и Dojo Toolkit. Но хватит лирики, давайте перейдем непосредственно к поиску. Для оного в JavaScript'е предусмотрены следующие методы (не в jQuery, не в Sizzle, а в JavaScript):

getElementById(id)

поиск по id="…"

getElementsByName(name)

поиск по name="name" и id="name"

getElementsByClassName(class)

поиск по class="class"

getElementsByTagName(tag)

поиск по имени тега

querySelectorAll(selector)

поиск по произвольному CSS-селектору

Пробежавшись беглым взглядом по списку, можно заметить метод querySelectorAll() – он универсален и действительно удобен. И именно этот метод библиотека пытается вызвать, когда вы скармливаете что-то в качестве селектора в jQuery, но данный метод иногда нас подводит, и тогда на сцену выходит Sizzle во всей красе, вооруженный всеми упомянутыми методами, да ещё со своим уникальным арсеналом:

if (document.querySelectorAll) (function(){
    var oldSelect = select;
    /* ... */
    select = function( selector, context, results, seed, xml ) {

    // используем querySelectorAll когда нет фильтров в запросе,
    // когда это запрос не по xml-объекту,
    // и когда не обнаружено проблем с запросом
    // ещё есть пара проверок, которые я опустил для наглядности

    try {    
        push.apply(
            results,            
            slice.call(context.querySelectorAll( selector ), 0)        
        );
        return results;
    } catch(qsaError) { /* подвёл, опять, ну сколько можно */ }
        /* ... */
        // выход Sizzle
        return oldSelect( selector, context, results, seed, xml );
    };
});

Но давайте уже рассмотрим, как Sizzle ищет в DOM, если-таки метод document.querySelectorAll() споткнулся. Начнём с разбора алгоритма работы на следующем примере:

$("thead > .active, tbody > .active")
  1. Получить первое выражение до запятой: «thead > .active»

  2. Разбить на кусочки: «thead», «>», «.active»

  3. Найти исходное множество элементов по последнему кусочку (все «.active»)

  4. Фильтровать справа налево (все «.active» которые находятся непосредственно в «thead»)

  5. Искать следующий запрос после запятой (возвращаемся к первому пункту)

  6. Оставить только уникальные элементы в результате

Глядя на данный алгоритм вы должны заметить, что правила читаются справа налево!

Копаем глубже. При анализе даже самого маленького выражения есть несколько нюансов, на которые стоит обратить внимание. Первый – это приоритет поиска, он различен для различных браузеров (в зависимости от их возможностей, или «невозможностей»):

{
    order: new RegExp( "ID|TAG" +
        (assertUsableName ? "|NAME" : "") +
        (assertUsableClassName ? "|CLASS" : "")
    )
}

Не обращайте внимание на RegExp – это внутренняя кухня Sizzle.

Таким образом, рассматривая выражение div#my, Sizzle найдёт вначале элемент с id="my", а потом уже проверит на соответствие с <div>. Хорошо, это вроде как фильтрация, и она тоже соблюдает очерёдность – это второй нюанс:

{
    preFilter: {    
        "ATTR": function (match) { /* ... */ },
        "CHILD": function (match) { /* ... */ },
        "PSEUDO": function (match) { /* ... */ }
    },    
    filter: {    
        "ID": function (id) { /* ... */ },
        "TAG": function (nodeName) { /* ... */ },
        "CLASS": function (className) { /* ... */ },
        "ATTR": function (name, operator, check) { /* ... */ },
        "CHILD": function (type, argument, first, last) { /* ... */ },
        "PSEUDO": function (pseudo, argument, context, xml) { /* ... */ }
    }
}

Третий нюанс – это относительные фильтры, которые работают сразу с двумя элементами (они вам знакомы по CSS-селекторам):

{
    relative: {    
        ">": { dir: "parentNode", first: true },    
        " ": { dir: "parentNode" },    
        "+": { dir: "previousSibling", first: true },    
        "~": { dir: "previousSibling" }    
    }
}

Ой, зачем я вас всем этим гружу? Почитайте лучше об оптимизации запросов в следующем главе.

Официальная документация по библиотеке Sizzle доступна на .

Sizzle
GitHub'е проекта