Выборка CSS-селекторов. Реализация логики CSS3-селекторов. Технологии будущего. Оптимизация структуры веб-страниц
Примеры вызовов
Еще один велосипед
Выборка CSS-селекторов
От простого к сложному
Перебор массива
Уникальность элементов
Подводя черту
Насчет с самого простого: чего мы хотим добиться? Мы хотим, задав произвольную строку CSS-селектора, соответствующую спецификации (http://www.w3.org/TR/2005/WD-css3-selectors-20051215/), получить на выходе массив из всех элементов, соответствующих этой самой строке. Вроде пока все просто.
В качестве иллюстрации спецификации можно примести следующие примеры (работает во всех современных браузерах и IE8+):
// вернет элемент с идентификатором my_id
querySelectorAll('#my_id')
// вернет все элементы с классом external
querySelectorAll('.external')
// вернет все абзацы на странице
querySelectorAll('p')
Однако уже тут можно отметить один момент: очень часто нам нужно выбрать просто элемент по его идентификатору или найти все элементы с определенным классом. Эти операции встречаются достаточно часто во всех JavaScript-библиотеках, поэтому они должны выполняться максимально быстро. Запускать весь механизм анализа входной строки селектора просто в том случае, когда нам нужно вернуть один-единственный элемент, заданный с помощью идентификатора, крайне неосмотрительно. Здесь мы можем воспользоваться принципом ленивого программирования: «не делай того, чего можно не делать», — и достаточно сильно ускорить работу для простейших случаев.
Если посмотреть на современные JavaScript-библиотеки, то везде такая проверка уже осуществляется с помощью регулярного выражения. И тут сразу же небольшая хитрость: инициализация любого регулярного выражения обходится достаточно дорого в браузерах (хотя сложность выражения начинает влиять на затраченное время только при большой его длине), и разумно было бы вообще без него обойтись. И когда можно обойтись indexOf для проверки подстроки — этим (в элементарных случаях) всегда нужно пользоваться.
Может так случиться, что регулярное выражение обеспечивает корректность, и замена его никак не приведет к потере читаемости кода и непонятному выигрышу (или даже проигрышу) в скорости выполнения. Тогда можно заменить, например, exec на связку test и charAt / substr: это позволит увеличить производительность примерно на 20%. Если данный участок кода выполняется в цикле многократно, это может оказаться достаточно существенным.
В YASS данная задача решена следующим образом:
// проверяем, удовлетворяем ли селектор простому случаю
if (/^[\w[:#.][\w\]*^|=!]*$/.test(selector)) {
// в случае положительного результата инициализируем переменную,
// которая отвечает за '#', '.' , ':' или '[' в начале селектора
var firstLetter = selector.charAt(0);
...
}