JavaScript: Выбор по селектору
Частой задачей при работе с деревьями (особенно HTML), является необходимость выбрать список узлов по определенному критерию.
Пара примеров из реальной жизни:
XPath
/bookstore/book/price[text()]
price/@exchange/total
book[excerpt]/author[degree]
JQuery
$("ul > li:first-child")
$("p.class1, #p1")
solution.js
Реализуйте и экспортируйте по умолчанию функцию, которая возвращает список нод в соответствии с запросом. Запрос это список из имен тегов, в котором каждый следующий тег это тег, вложенный в предыдущий. Порядок, в котором ноды возвращаются - не важен.
У нас есть такой HTML:
<h1>scheme</h1>
<p>is a lisp</p>
<p>
<ul>
<li>item 2</li>
<li>item 1</li>
</ul>
</p>
<ol>
<li>item 2</li>
<li>item 1</li>
</ol>
<p>is a functional language</p>
<ul>
<li>item</li>
</ul>
<div>
<p>another text</p>
</div>
<div>
<div>
<p>
<span>text</span>
</p>
</div>
</div>
<div>
<a>
<div>
<p>
<span>text</span>
</p>
</div>
</a>
</div>
<h1>prolog</h1>
<p>is about logic</p>
Строим HTML следующим образом:
const dom1 = make();
const dom2 = append(dom1, node('h1', 'scheme'));
const dom3 = append(dom2, node('p', 'is a lisp'));
const children1 = l(node('li', 'item 1'), node('li', 'item 2'));
const dom4 = append(dom3, node('p', l(node('ul', children1))));
const children2 = l(node('li', 'item 1'), node('li', 'item 2'));
const dom5 = append(dom4, node('ol', children2));
const dom6 = append(dom5, node('p', 'is a functional language'));
const children3 = l(node('li', 'item'));
const dom7 = append(dom6, node('ul', children3));
const dom8 = append(dom7, node('div', l(node('p', 'another text'))));
const dom9 = append(dom8, node('div', l(node('div', l(node('p', l(node('span', 'text'))))))));
const dom10 = append(dom9, node('div', l(node('a', l(node('div', l(node('p', l(node('span', 'text'))))))))));
const dom11 = append(dom10, node('h1', 'prolog'));
dom = append(dom11, node('p', 'is about logic'));
Пример работы функции, где для наглядности показано какой она будет возвращать результат если выводить его на экран (htmlToString()
):
select(l('p', 'ul', 'li'), dom);
// <li>item 1</li><li>item 2</li>
select(l('div', 'div', 'p'), dom);
// <p><span>text</span></p>
select(l('div', 'p'), dom);
// <p>another text</p><p><span>text</span></p><p><span>text</span></p>
select(l('div'), dom));
// <div><a><div><p><span>text</span></p></div></a></div><div><p><span>text</span></p></div><div><div><p><span>text</span></p></div></div><div><p><span>text</span></p></div><div><p>another text</p></div>
Алгоритм работы функции
- Список тегов для поиска будем называть словом
query
. query
ищется с любого уровня дерева, а не только с верхнего. Например, если нашquery
этоp
, то будут найдены всеp
на всех уровнях.- Производится поиск только подряд идущих тегов, например, если запрос
l('ul', 'li')
, то будут найдены только теli
, которые идут сразу заul
.
Подсказки
hasChildren()
- функция, которая проверяет, есть ли потомки у элементаchildren()
- функция, которая возвращает список потомков
P.S. В целом, эта функция достаточно сложна и, если вы сможете решить эту задачу самостоятельно, то вас смело можно брать на работу).
Для полного доступа к испытанию нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Отзывы

Создание абстракции в решении учителя - уровень БОГ!
Код, не требующий комментариев, одним словом!
Принцип "разделяй и властвуй" во всей его красе, браво!
Я еще никогда не писал так много ифов :D
Кто не смог решить, не отчаивайтесь, обязательно загляните сюда снова после второго проекта!
За примером, где нет ни одной абстракции - сюда :)

https://ru.hexlet.io/code_reviews/46960 Ох, ну теперь меня, старого коня, точно на работу возьмут! )) Полтора часа делов.