Вопросы на собеседовании frontend-разработчика: ответы и задачи
Вопросы для frontend-собеседования: HTML, CSS, JavaScript, TypeScript и React. Короткие ответы, задачи на event loop и API, план подготовки по грейдам.
На frontend-собеседовании полезно уметь не только дать определение, но и применить его: объяснить порядок вывода JavaScript, собрать доступную форму, обработать ошибки API и обосновать устройство React-компонента. Ниже — вопросы с короткими ответами, практические задачи и план подготовки. Это тренировочная подборка, а не список вопросов конкретного работодателя и не гарантия прохождения интервью.
Начните с требований своей вакансии: React здесь — пример фреймворка, а не обязательный стек для любого frontend-интервью. По общему плану подготовки к собеседованию уточните формат встречи, соберите истории о проектах и вопросы работодателю. Затем проверьте технические темы ниже.
HTML и CSS
Что такое семантическая вёрстка? Использование тегов по смыслу: header,
nav, main, article, section, footer вместо сплошных div. Это улучшает
доступность (скринридеры), SEO и читаемость разметки.
Что такое box model? Модель коробки: контент окружён padding, затем
border, затем margin. По умолчанию ширина считается без padding и border;
box-sizing: border-box включает их в заданную ширину — так удобнее верстать.
Чем flexbox отличается от grid? Flexbox — одномерная раскладка (строка или колонка), хорош для выравнивания элементов по одной оси. Grid — двумерная (строки и колонки одновременно), для сеток и сложных макетов.
Как работает специфичность селекторов? Внутри сопоставимых правил каскада
сравниваются количества id, затем классов/атрибутов/псевдоклассов, затем тегов.
При равенстве выигрывает более позднее правило. Сначала учитываются происхождение,
важность и слои каскада: !important — не дополнительный «вес» селектора.
Inline-стили имеют отдельный приоритет, но не побеждают абсолютно все правила.
Какие бывают значения position? static (по умолчанию), relative
(смещение относительно себя), absolute (относительно ближайшего позиционированного
предка), fixed (относительно окна), sticky (прилипает при прокрутке).
JavaScript
Какие типы данных есть в JavaScript? Примитивы: string, number, bigint,
boolean, undefined, null, symbol — и объекты (object, включая массивы и
функции). Исторический нюанс: typeof null === 'object'.
Чем == отличается от ===? == сравнивает с приведением типов (1 == '1'
истинно), === — без приведения, и значение, и тип. На практике используют ===.
Что такое замыкание (closure)? Функция вместе с её лексическим окружением: она сохраняет доступ к переменным внешней функции даже после её завершения. На замыканиях строят приватные переменные, счётчики, debounce и throttle.
Что такое hoisting? Подъём объявлений в начало области видимости. Объявления
var инициализируются как undefined, а let/const попадают во «временную
мёртвую зону» (TDZ) и до объявления недоступны.
В чём разница между var, let и const? var — функциональная область
видимости и hoisting. let и const — блочная область и TDZ. const запрещает
переприсваивание переменной, но сам объект, на который она ссылается, остаётся
изменяемым.
Как определяется this? В обычной функции this зависит от способа вызова
(кто вызвал). В стрелочной функции this лексический — берётся из окружения, где
функция объявлена, и не меняется.
Как работает прототипное наследование? У объектов есть ссылка на прототип
([[Prototype]]). Если свойства нет в самом объекте, движок ищет его в прототипе
и дальше по цепочке прототипов до null.
Что такое event loop? В браузере он координирует задачи, микрозадачи и
обновление интерфейса. После текущей задачи, когда стек пуст, очередь микрозадач
выполняется до опустошения, включая новые микрозадачи. Затем браузер может обновить
отображение и выбрать следующую задачу. Promise.then и queueMicrotask ставят
микрозадачи, а setTimeout — отдельную задачу; задержка таймера не гарантирует точное время запуска.
Что такое Promise и async/await? Promise — объект, представляющий
будущий результат асинхронной операции (pending → fulfilled/rejected).
async/await — синтаксис поверх промисов: await приостанавливает функцию до
разрешения промиса, делая асинхронный код похожим на синхронный.
Зачем нужны debounce и throttle? Это приёмы ограничения частоты вызовов.
debounce откладывает вызов до паузы в событиях (поиск по вводу), throttle
пропускает не чаще раза в интервал (обработка scroll/resize).
React
Что такое виртуальный DOM? Представление интерфейса в памяти. При изменении состояния React вычисляет новое дерево, сопоставляет его с предыдущим и применяет необходимые изменения к DOM. Вызов компонента не означает пересоздание всех его DOM-узлов. Производительность зависит от работы приложения, а не от одного наличия Virtual DOM.
Какие правила у хуков? Хуки вызывают только на верхнем уровне компонента (не в условиях и циклах) и только из React-компонентов или других хуков. Это нужно, чтобы React сопоставлял состояние по порядку вызова.
Зачем массив зависимостей в useEffect? Эффект синхронизирует компонент с
внешней системой после commit. Без массива setup запускается после каждого commit
компонента; с массивом — если зависимость изменилась по Object.is. Включайте все
используемые реактивные значения, а не скрывайте их ради нужной частоты запуска.
При [] нет реактивных зависимостей, но перемонтирование запускает эффект заново,
а Strict Mode при разработке может дополнительно выполнить setup → cleanup → setup.
Cleanup освобождает ресурс перед повторным setup и при размонтировании.
Зачем нужны ключи (key) в списках? Ключи дают элементам стабильную
идентичность, чтобы React при реконсиляции понимал, что изменилось. Индекс
массива как ключ — плохая идея, если список меняет порядок или длину.
Чем controlled-компонент отличается от uncontrolled? В controlled значение
поля хранится в состоянии React и управляется через value + onChange. В
uncontrolled значение живёт в самом DOM и читается через ref.
Зачем нужны React.memo, useMemo, useCallback? Чтобы избегать лишних
ререндеров и пересчётов. React.memo мемоизирует компонент, useMemo —
результат вычисления, useCallback — ссылку на функцию. Применять точечно, где
перерисовки реально дорогие.
TypeScript, доступность и работа с API
Чем unknown отличается от any? any отключает проверку операций над
значением. unknown требует сначала сузить тип — например, проверкой typeof
или валидатором. Ответ API нельзя считать надёжным только потому, что вы написали
as User: утверждение типа не проверяет данные во время выполнения.
Как описать состояния загрузки? Вместо независимых флагов можно использовать
discriminated union: { status: 'loading' }, { status: 'success', data: User[] }
или { status: 'error', message: string }. Проверка status сужает тип и
не позволяет читать data у ошибки. При необходимости отдельно добавляют состояния
до первого запроса и повторной загрузки с сохранёнными данными.
Что проверить у формы без мыши? Связь label с полем, порядок Tab,
видимый фокус, отправку с клавиатуры, понятные сообщения об ошибках и связь
ошибки с полем. Кликабельный div не заменяет button: семантический элемент
уже поддерживает ожидаемую клавиатурную механику.
Как обработать неуспешный fetch? Проверять response.ok: HTTP-ошибка
вроде 404 сама по себе не отклоняет промис fetch. Отдельно обработать сетевой
сбой, неверные данные и отмену запроса. Пользователь должен видеть загрузку,
ошибку или пустой результат, а не бесконечный спиннер.
Три практические задачи для самопроверки
1. Объясните порядок вывода
До запуска назовите порядок и обоснуйте каждую строку для браузера:
console.log('A')
setTimeout(() => console.log('B'), 0)
Promise.resolve().then(() => {
console.log('C')
queueMicrotask(() => console.log('D'))
})
console.log('E')
Ответ: A, E, C, D, B. Сначала выполняется синхронный код.
Обработчик промиса — микрозадача; добавленная им микрозадача тоже выполняется до
перехода к задаче таймера. Уточняющий вопрос: почему нулевая задержка не делает
таймер синхронным и что произойдёт, если микрозадачи бесконечно добавляют новые?
2. Спроектируйте поиск с запросом к API
Пользователь ввёл «rea», затем «react». Ответ на первый запрос пришёл последним. Как не заменить новые результаты устаревшими?
Разбор: debounce сокращает число запросов, но сам по себе не решает гонку.
Отменяйте предыдущий запрос через AbortController и защищайте применение результата
проверкой актуальности запроса или cleanup-флагом эффекта. При отмене не показывайте
пользователю обычную ошибку. Проверьте очистку строки, ошибку HTTP, пустую выдачу
и уход со страницы до завершения запроса.
3. Разберите собственный компонент
Возьмите форму из своего проекта. Объясните, где хранится состояние, как устроена валидация, что происходит при двойной отправке и как возвращается фокус после ошибки. Затем предложите проверку: успешная отправка, отказ сервера, неправильный ввод, работа с клавиатуры.
Сильный тренировочный ответ содержит не только решение, но и альтернативу: почему выбран этот способ и при каких условиях вы поменяли бы его. Если проекта ещё нет, сделайте учебную форму и прямо называйте опыт учебным.
Что спрашивают на разных грейдах
- Junior: объясните базовые HTML/CSS и JavaScript на примере, сверстайте форму, покажите обработку события и понятную ошибку. Не ограничивайтесь пересказом терминов.
- Middle: разберите состояние, типы данных API, гонки запросов, тестирование и диагностику лишних рендеров. Подготовьте пример бага и способ его обнаружения.
- Senior: обоснуйте архитектурный компромисс, границы модулей, доступность, измерение производительности и постепенное внедрение изменений. Покажите, как решение влияло на командную работу.
Это ориентиры для самопроверки: границы грейдов и формат оценки у компаний отличаются.
План подготовки и связь с резюме
- Сопоставьте темы с вакансией. Выпишите обязательный стек и отметьте, где можете дать ответ, написать пример и рассказать о собственной задаче.
- Решите практические задачи без подсказок. Сначала проговорите гипотезу, затем проверьте её в своей среде. Ошибки превратите в список тем для повторения.
- Подготовьте разбор проекта. Задача → ваша роль → решение → проверка → ограничения. Не раскрывайте закрытый код или конфиденциальные данные.
- Проверьте резюме. Каждый заявленный навык должен выдерживать уточняющие вопросы. Прожарка резюме помогает уточнить формулировки, но не заменяет знания и не подтверждает опыт за вас. Для структуры документа пригодится гайд по формату IT-резюме.
- Подготовьте отклик под роль. В гайде по сопроводительному письму с ИИ есть промпт и пример на frontend-задачах. Любой текст ИИ сверяйте с реальными проектами: нельзя добавлять технологии или результаты ради совпадения с вакансией.
Если используете автоматизацию поиска, отдельно проверьте версию резюме и параметры вакансий по пошаговому описанию JobTurbo. Подготовка, отредактированное резюме и отправленный отклик — разные этапы; ни один из них не гарантирует приглашение, успешное интервью или трудоустройство.
Перед обсуждением оффера сравните зарплатные ориентиры по своему направлению: Зарплата Frontend-разработчика; Зарплата JavaScript-разработчика. В каждой подборке указаны дата среза, размер выборки и методика расчёта.
Частые вопросы
Что такое замыкание (closure) в JavaScript?
Замыкание — это функция вместе с её лексическим окружением: она сохраняет доступ к переменным внешней функции даже после того, как та завершилась. На замыканиях строят приватные переменные, счётчики, мемоизацию, debounce и throttle.
Чем отличается == от === в JavaScript?
Оператор == сравнивает с приведением типов (например, 1 == '1' истинно), а === сравнивает без приведения — и значение, и тип. В коде почти всегда используют ===, чтобы избежать неожиданных приведений.
Что такое event loop в JavaScript?
В браузере event loop координирует выполнение задач и обновление интерфейса. После завершения текущей задачи и освобождения стека выполняется очередь микрозадач, включая добавленные в процессе. Затем браузер может обновить отображение и перейти к следующей задаче. Обработчики промисов и queueMicrotask — микрозадачи; setTimeout ставит отдельную задачу.
Что такое виртуальный DOM в React?
Это представление интерфейса в памяти. При обновлении React вычисляет новое дерево, сопоставляет его с предыдущим и применяет необходимые изменения к DOM. Рендер компонента не означает пересоздание всего DOM; наличие Virtual DOM само по себе не гарантирует более высокую производительность.
Зачем нужен массив зависимостей в useEffect?
Зависимости определяют повторный запуск эффекта после commit: без массива — после каждого commit компонента, с массивом — когда зависимость изменилась по Object.is. Пустой массив означает отсутствие реактивных зависимостей, но не обещает единственный запуск за всё время: возможны перемонтирование и дополнительный цикл setup/cleanup в Strict Mode при разработке. Cleanup выполняется перед повторным setup и при размонтировании.
Запустите автоотклик бесплатно
До 25 успешных откликов за скользящие 24 часа — без оплаты и привязки карты. AI подготовит сопроводительное под каждую подходящую вакансию.
Подключить JobTurbo →