15 вопросов с собеседований по фронтенду для мидлов
Пов: вы пришли на собес на мидла. В статье — ищите вопросы и пытайтесь ответить сначала сами. Если не получается — ответы и решения тоже есть.
3К открытий20К показов

Статей в духе «вопросы для фронтенд разработчика написано много». Опыт Альберта Халимова в прохождении и проведении собеседований показывает, что, задавая базовые вопросы, интервьюер хочет узнать, готовился ли человек и насколько он заинтересован в работе.
На типичные вопросы Junior-разработчик должен легко ответить. Вместе с Альбертом Халимовым, TeamLead Frontend Developer в Группе М.Видео-Эльдорадо и ментором Эйч Навыки, разбираемся в тех же вопросах, но смотрим на них под другим углом и узнаем самое главное — готовы ли быть мидлом.

Альберт Халимов
TeamLead Frontend Developer в Группе М.Видео-Эльдорадо и ментор Эйч Навыки
1. Что такое оператор typeof?
Вызов typeof x возвращает строку с именем типа:
2. Что вернет typeof null, typeof new Date, typeof alert?
Date — это встроенный объект, который содержит дату и время, а также предоставляет методы управления ими.
Результатом вызова typeof null является "object". Это официально признанная ошибка в typeof, берущая начало еще со времен создания JavaScript и сохраненная для совместимости. Конечно, null — не объект. Это специальное значение с отдельным типом.
Вызов typeof alert возвращает "function", потому что alert — функция. Функции относятся к объектному типу. Но typeof обрабатывает их особым образом, возвращая "function". Так тоже повелось с момента создания JavaScript. Формально это неверно, но может быть удобным на практике.
Интересный факт: информация об операторе typeof — это последний пункт главы «Типы данных» на https://learn.javascript.ru/.
3. Что такое NaN? Какого типа это значение? Как можно узнать, равно ли значение переменной NaN?
NaN расшифровывается как "Not A Number", это "false" (ложное) значение. Будьте аккуратны: выражение typeof NaN
возвращает тип Number
. Чтобы проверить значение переменной на соответствие NaN, нужно воспользоваться встроенным методом isNaN()
или оператором тройного равенства ===
.
4. Какие есть способы объявления функций? В чем их отличия? Что такое стрелочная функция?
Ниже рассмотрим ключевые отличия Function Declaration от Function Expression.
Во-первых, синтаксис: Function Declaration — функция объявляется отдельной конструкцией function…
в основном потоке кода.
Function Expression — функция, созданная внутри другого выражения или синтаксической конструкции. В данном случае функция создается в правой части «выражения присваивания» =
:
Более тонкое отличие появляется тогда, когда функция создаётся движком JavaScript. Так, Function Expression появляется в то время, как выполнение доходит до него, и затем уже может использоваться.
После того, как поток выполнения достигнет правой части выражения присваивания let sum = function…
, функция считается созданной и может быть использована (присвоена переменной, вызвана и т.д. ).
С Function Declaration всё иначе. Она может быть вызвана раньше, чем объявлена. Другими словами, когда движок JavaScript готовится выполнять скрипт или блок кода, прежде всего, он ищет в нём Function Declaration и создаёт все такие функции. Можно считать этот процесс «стадией инициализации».
Только после того, как все объявления Function Declaration будут обработаны, продолжится выполнение. В результате функции, созданные как Function Declaration, могут быть вызваны раньше своих определений.
Например, будет работать так:
Функция sayHi была создана, когда движок JavaScript подготавливал скрипт к выполнению, и такая функция видна повсюду в этом скрипте.
Если бы это было Function Expression, то такой код вызвал бы ошибку:
Функции, объявленные при помощи Function Expression, создаются тогда, когда выполнение доходит до них. Это случится только на строке, помеченной звёздочкой (*). Слишком поздно.
Ещё одна важная особенность Function Declaration заключается в её блочной области видимости.
В строгом режиме, когда Function Declaration находится в блоке {...}, функция доступна везде внутри блока, но не снаружи.
Для примера давайте представим, что нам нужно объявить функцию welcome()
в зависимости от значения переменной age
, которое мы получим во время выполнения кода. И затем запланируем использовать её когда-нибудь в будущем.
Если мы попробуем использовать Function Declaration, это не заработает так, как задумывалось:
Это произошло, так как объявление Function Declaration видно только внутри блока кода, в котором располагается.
Вот ещё один пример:
Что можно сделать, чтобы welcome была видна снаружи if
? Верным подходом будет воспользоваться функцией, объявленной при помощи Function Expression, и присвоить значение welcome
переменной, объявленной снаружи if
, что обеспечит нам нужную видимость.
Такой код заработает, как ожидалось:
Или мы могли бы упростить это ещё сильнее, используя условный оператор:
Так когда использовать Function Declaration, а когда Function Expression?
Как правило, если нам понадобилась функция, нужно рассматривать синтаксис Function Declaration, который мы использовали до этого. Он даёт больше свободы в том, как мы можем организовывать код. Функции, объявленные таким образом, можно вызывать до их объявления.
Также функции вида function f(…) {…}
чуть более заметны в коде, чем let f = function(…) {…}
. Function Declaration легче «ловятся глазами».
…Но если Function Declaration нам не подходит по какой-то причине или нам нужно условное объявление (мы рассмотрели это в примере выше), то следует использовать Function Expression.
5. Что такое функции высшего порядка? Приведите примеры.
Функции высшего порядка — это функции, которые могут:
- Принимать функции в качестве аргументов.
- Возвращать функции как результат своей работы.
Вот встроенные функции высшего порядка в JavaScript:
map()
— применяет функцию ко всем элементам массива.filter()
— фильтрует элементы массива на основе условия.reduce()
— сводит массив к одному значению, применяя функцию.
6. Что такое Promise и какие бывают состояния?
Promise — объект в JavaScript, который представляет результат асинхронной операции. Промис позволяет обрабатывать результат операции, когда он станет доступным, вместо того, чтобы блокировать выполнение кода и ожидать завершения операции.
Промис может находиться в одном из трех состояний:
- Pending — исходное состояние промиса. Он находится в ожидании выполнения или отклонения операции.
- Fulfilled — промис переходит в это состояние, когда операция успешно завершается.
- Rejected — промис переходит в это состояние, когда операция завершается с ошибкой. Здесь промис возвращает причину ошибки.
Пример:
7. Как сравнивать в JS? Как сравнить два массива?
Когда вы сравниваете примитивные типы (числа, строки, булевы значения и т.д.), используются операторы ==
(нестрогое сравнение) и ===
(строгое сравнение).
==
проверяет равенство значений после приведения типов.
===
проверяет как равенство значений, так и типов (без приведения типов).
При сравнении массивов в JavaScript важно помнить, что массивы — это объекты, и сравнение происходит по ссылке. То есть два массива будут равны только в том случае, если они указывают на одну и ту же ссылку в памяти.
Можно преобразовать массивы в строки JSON и сравнить их. Это удобный способ, но он имеет несколько ограничений (например, порядок элементов в массиве имеет значение).
Для более точного сравнения массивов (в том числе с вложенными структурами) можно пройтись по каждому элементу массива с помощью цикла for
или методов every/some
.
8. Чем отличаются any, unknown и never?
Основные различия:
any
: можно присваивать любые значения, без проверки типа.unknown
: можно присваивать любые значения, но необходимо проверять тип перед использованием.never
: тип для значений, которые не могут существовать, например, функции, которые не возвращают ничего.
9. Что такое CORS и как его можно решить на фронтенде?
CORS — механизм безопасности, который предотвращает доступ к данным с других источников. Чтобы решить проблемы с CORS:
- На фронтенде можно использовать прокси-серверы для разработки.
- В продакшн-окружении необходимо настроить CORS на сервере.
- Если вы не контролируете сервер, то решением будет обращение к разработчикам API или использование серверного прокси для обхода ограничений.
10. Что такое Progressive Web Apps (PWA)? Зачем нужно?
Progressive Web Apps (PWA) — тип веб-приложений, который использует современные веб-технологии для предоставления пользователям опыта, схожего с нативными мобильными приложениями, но через обычный веб-браузер. PWA можно использовать в любом браузере, который поддерживает стандарты веба. Такие приложения могут работать оффлайн, присылать пуши, быстро загружаться и подстраиваться под любой браузер, который поддерживает эти фичи. Из примеров — банковские веб-приложения, которые можно установить на экран.
Вот главные особенности PWA:
- Работа в оффлайн-режиме (Offline-first). PWA используют Service Workers, которые позволяют веб-приложению работать даже без интернета. Это значит, что приложение может кешировать данные и ресурсы, обеспечивая доступность контента в оффлайн-режиме или при плохом интернет-соединении.
- Установка на устройство (Installable). PWA можно устанавливать на устройства как нативные приложения. При этом скачивать их из магазина пользователю не нужно.
- Push-уведомления. PWA могут отправлять push-уведомления — так пользователь может получать информацию, даже если приложение закрыто.
- Обновления. Приложения могут автоматически обновляться в фоновом режиме.
- Мгновенная загрузка. PWA загружаются быстрее, так как они используют кэширование ресурсов и данных через Service Workers — это улучшает производительность даже при медленном интернете.
- Универсальность. PWA работают на всех платформах (мобильные устройства, десктопы, планшеты) и в любых браузерах, которые поддерживают современные веб-стандарты (например, Chrome, Firefox, Safari, Edge и т.д.).
11. Lifecycle во Vue: когда использовать хуки жизненного цикла?
В Vue 2 жизненный цикл выглядит следующим образом:
beforeCreate
→ created
→ beforeMount
→ mounted
→ beforeUpdate
→ updated
→ beforeDestroy
→ Destroyed
В Vue 3 жизненный цикл был немного изменен и улучшен. Некоторые хуки переименованы:
beforeDestroy
→ beforeUnmount
destroyed
→ unmounted
Кроме того, в Vue 3 появилась возможность использовать Composition API, который предоставляет более гибкий способ организации жизненного цикла компонентов. Теперь можно создавать компоненты с помощью функции setup()
.
Когда использовать хуки жизненного цикла?
beforeCreate
иcreated
используются для настройки данных, свойств или методов компонента до и после его создания.beforeMount
иmounted
полезны для операций, которые необходимо выполнить при рендере компонента (например, вызов API, настройка сторонних библиотек, или выполнение начальной логики).beforeUpdate
иupdated
можно использовать для наблюдения за изменениями данных или для манипуляций с DOM до или после его обновления.beforeDestroy
иdestroyed
(или beforeUnmount и unmounted в Vue 3) полезны для очистки ресурсов перед уничтожением компонента.
12. В каком компоненте отработает mounted вначале — дочернем или родительском?
В Vue.js хук mounted вызывается для компонента, как только его DOM вставляется в дерево DOM. Когда компонент — часть иерархии (например, родительский и дочерний компоненты), хуки жизненного цикла выполняются в определенном порядке.
Хук mounted будет вызван для дочернего компонента перед родительским.
Объяснение: родительский компонент инициирует рендеринг и монтирование дочернего компонента. Когда Vue монтирует компоненты, он сначала монтирует все дочерние компоненты, а потом родительский компонент. Это связано с тем, что родительский компонент ждет завершения монтирования дочерних компонентов, чтобы их правильно вставить в DOM.
13. Как изменить commit message
1. Изменить последний коммит
Если нужно изменить сообщение только последнего коммита, используйте команду:
git commit --amend
После этого Git откроет редактор, где вы сможете изменить сообщение коммита. Сохраните изменения и выйдите из редактора.
2. Изменить старый коммит
Если нужно изменить сообщение не последнего коммита, а более старого, можно воспользоваться rebase:
git rebase -i <commit_id>
Здесь <commit_id> — идентификатор коммита, сообщение которого вы хотите изменить. Можно использовать git log для получения ID нужного коммита. В открывшемся файле замените слово pick на reword напротив коммита, который хотите изменить, и сохраните файл. Git откроет редактор для изменения сообщения этого коммита. После редактирования сохраните и выйдите.
Завершите процесс rebase:
git rebase --continue
3. Изменить сообщение в уже отправленном коммите (Push)
Если коммит был уже отправлен в удаленный репозиторий, а вы хотите изменить сообщение коммита, то вам нужно будет форсировать пуш.
Измените коммит с помощью git commit --amend
или git rebase -i
.
После изменения выполните принудительный пуш:
git push --force
Пожалуйста, перед собеседованием повторите CSS. Многие разработчики усиленно готовятся к технической сессии по JS, TS, своему фреймворку, но забывают о верстке. Если вам повезет работать над новым продуктом, то верстка будет занимать больше половины времени.
14. Что такое псевдоклассы в CSS? Как обратиться к псевдоклассу в JS?
Псевдоклассы в CSS — стили, которые применяются к элементам в зависимости от их состояния или структуры в документе.
В JavaScript нельзя напрямую изменить псевдоклассы, но можно использовать селекторы CSS для выбора элементов с псевдоклассами. Это делается с помощью методов по типу querySelector
и querySelectorAll
.
15. Что такое dvh, lvh, em и rem в CSS? Когда и почему лучше использовать каждую из этих единиц измерения?
Эти единицы были введены в спецификации CSS, чтобы улучшить работу с адаптивным дизайном и обеспечить корректное отображение на мобильных устройствах.
- dvh (dynamic viewport height) — единица измерения, которая учитывает динамические изменения в размерах окна, например, высота при открытии клавиатуры на мобильных устройствах.
- lvh (large viewport height) — единица измерения, которая использует максимальную высоту вьюпорта, независимо от динамических изменений (например, не учитывает изменения, связанные с клавиатурой на мобильных устройствах).
Когда использовать:
- dvh полезен, когда нужно учитывать изменения размера окна при взаимодействии с мобильными устройствами (например, при открытии клавиатуры).
- lvh полезен для работы с мобильными устройствами, когда нужно обеспечить стабильный дизайн, не зависящий от изменения высоты вьюпорта из-за динамических изменений.
- em — это единица измерения, которая зависит от размера шрифта родительского элемента. 1em равен текущему размеру шрифта родительского элемента. Если в родительском элементе установлен шрифт размером 16px, то 1em будет равен 16px.
- rem — это единица измерения, которая зависит от размера шрифта корневого элемента (<html>). 1rem равен размеру шрифта, установленному на корневом элементе (по умолчанию в большинстве браузеров это 16px).
Когда и зачем использовать каждую из этих единиц?
- dvh/lvh: Используйте, если вам нужно учитывать динамическое изменение высоты вьюпорта (например, на мобильных устройствах при открытии клавиатуры) или если вам нужно работать с максимальной высотой вьюпорта, независимо от динамических изменений.
- em: Используйте, когда размеры элементов должны зависеть от размера шрифта родительского элемента. Это полезно для создания гибких и адаптивных макетов, которые изменяются с размером шрифта.
- rem: Используйте, когда нужно, чтобы размеры были относительно размера шрифта корневого элемента. Так проще поддерживать единообразие и легко масштабировать весь интерфейс.
Если вы знали ответы на все вопросы, поздравляем — можете гордо считать себя мидлом и смело ходить на собеседования. Если в каких-то вопросах плаваете, то подучите теорию и порешайте побольше задачек/почитайте код других разработчиков — тогда все получится.
На все ответили?
Да, я такое как орешки щелкаю!
На что-то ответил, но вопросы не из легких...
3К открытий20К показов