Как реализовать функцию, принимающую селектор и возвращающую объект с методами для добавления классов и навешивания событий
Что проверяют
По сути вас просят написать маленький jQuery. Смотрят, как вы работаете с DOM API, замыканиями и ссылками на функции. Следом обычно спрашивают, как поддержать цепочку вызовов и как снять обработчик.
Как отвечать
Каркас: функция $(selector) находит элементы и возвращает объект с методами, который держит их в замыкании.
- поиск:
document.querySelectorAll(selector), а неquerySelector. Селектор.itemобычно подразумевает все элементы, и методы должны работать со всеми.NodeListпревращают в массив черезArray.fromили перебираютforEach; - классы:
el.classList.add(...classNames)принимает несколько классов сразу. Строку с пробелом передать нельзя,DOMTokenListброситInvalidCharacterError, поэтому её заранее режут по пробелам; - события:
addEventListener(type, handler, options). Черезoptionsпередают{ once: true },passiveилиsignalотAbortController, и тогда одинcontroller.abort()снимает все подписки сразу; - цепочка: каждый метод возвращает сам объект. Если методы объявлены стрелками,
thisна объект не указывает, поэтому возвращайте переменную с объектом, напримерapi; - пустой результат: jQuery на ненайденный селектор возвращает пустую коллекцию, и вызовы молча ничего не делают. Бросать исключение тоже допустимо, но это решение стоит проговорить.
Хорошо упомянуть делегирование: вместо обработчика на каждом из сотни элементов один обработчик на родителе и проверка event.target.closest(selector). Так работают и элементы, которые добавят в DOM позже.
Где спотыкаются
Пытаются снять обработчик новой анонимной функцией: off('click', () => ...). removeEventListener сравнивает ссылки, и такая функция не совпадёт с добавленной. Нужно хранить ссылку или использовать AbortController.
Берут querySelector и работают только с первым элементом, хотя селектор по классу подразумевает несколько.
Забывают, что removeEventListener учитывает флаг capture. Обработчик, добавленный с { capture: true }, без того же флага не снимется.