Уникальность элементов. Реализация логики CSS3-селекторов. Технологии будущего. Оптимизация структуры веб-страниц
Примеры вызовов
Еще один велосипед
Выборка CSS-селекторов
От простого к сложному
Перебор массива
Уникальность элементов
Подводя черту
Одной из основных проблем в ходе выбора элементов по CSS-селектору является корректность конечного набора. В случае div p у нас могут оказаться вложенные div, и если мы просто переберем все родительские элементы и объединим получившиеся дочерние, то конечный набор будет содержать дубли. Чтобы избежать такого рода ошибок нам нужно как-то отмечать элементы, которые мы выбрали.
Это стандартная задача, и решается она, в принципе, тоже стандартно: во всех библиотеках заводится определенное свойство DOM-узлов, которое отвечает за состояние «выбран». У этого подхода есть несколько минусов (например, нужно расширить это решение на случай асинхронных выборок элементов и понимать, что каждое обращение к элементам дерева ресурсоемко), но в подавляющем большинстве случаев оно позволяет устранить неуникальность элементов.
Схематично представить работу данного флага можно следующим образом.
for (child in children) {
if (!children[child].yeasss) {
if (last) {
children[child].yeasss = 1;
}
newNodes = children[child];
}
}
В процессе перебора нужных нам дочерних узлов мы проверяем, выставлен ли у этого потомка флаг yeasss (естественно, что кроме этой проверки мы должны удостовериться, что данный потомок нам действительно нужен). Далее мы выставляем флаг только в том случае, если работаем с последним звеном в цепочке «детей-родителей», и записываем дочерний узел в массив новых узлов, которые станут «родителями» на следующей итерации цикла.
Прекрасно видно, что флаг yeasss будет выставлен только в том случае, если мы работаем с последним звеном: для промежуточных звеньев он никогда не будет выставлен, поэтому на родительские элементы мы никакие ограничения не распространяем. Вполне возможно, что можно было бы сокращать массив родителей на каждой итерации (чтобы не выбирать заведомо один и те же элементы), однако, данный шаг не увеличит (в общем случае только уменьшит) производительность выборок, поэтому здесь такой подход и не используется.
Сброс флага (о котором шла речь в предыдущем разделе) осуществляется уже для окончательного массива элементов (после завершения всех циклов) и необходим как для корректности дальнейших выборок, так и для предотвращения утечек памяти в IE (расширенные свойства элементов вызывают микро-утечки в IE6/7).