15 вопросов с собеседований по фронтенду для мидлов
Пов: вы пришли на собес на мидла. В статье — ищите вопросы и пытайтесь ответить сначала сами. Если не получается — ответы и решения тоже есть.
5К открытий29К показов
Статей в духе «вопросы для фронтенд разработчика написано много». Опыт Альберта Халимова в прохождении и проведении собеседований показывает, что, задавая базовые вопросы, интервьюер хочет узнать, готовился ли человек и насколько он заинтересован в работе.
На типичные вопросы 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: Используйте, когда нужно, чтобы размеры были относительно размера шрифта корневого элемента. Так проще поддерживать единообразие и легко масштабировать весь интерфейс.
Если вы знали ответы на все вопросы, поздравляем — можете гордо считать себя мидлом и смело ходить на собеседования. Если в каких-то вопросах плаваете, то подучите теорию и порешайте побольше задачек/почитайте код других разработчиков — тогда все получится.
На все ответили?
Да, я такое как орешки щелкаю!
На что-то ответил, но вопросы не из легких...
5К открытий29К показов





