Співбесіда з JavaScript: питання та практика голосом
Ця сторінка для фронтенд- і фулстек-розробників, які знають JavaScript, але хочуть упевнено пояснювати його на співбесіді. Оберіть рівень або завантажте резюме чи вакансію, дайте відповідь голосом на питання (до 50) і отримайте звіт з оцінкою технічної точності, повноти та ясності. Нижче — типові питання на співбесіді JavaScript: від областей видимості та приведення типів до event loop, витоків пам’яті й архітектури асинхронного коду.
Про що питає ШІ-інтерв’юер
Області видимості та замикання
var проти let/const, блочна область видимості, hoisting і temporal dead zone, як замикання утримує змінні. Класика — setTimeout у циклі.
this, прототипи та класи
Як місце виклику визначає this, чим відрізняються стрілкові функції і як синтаксис class лягає на ланцюжок прототипів.
Event loop і мікрозадачі
Стек викликів, черга задач і черга мікрозадач, де в цьому циклі рендеринг. Задачі «що виведе код» із setTimeout і промісами — стандарт.
Проміси та async/await
Стани промісів і ланцюжки, Promise.all/allSettled/race/any, обробка помилок з await, паралельний запуск замість послідовного.
Типи та приведення типів
Примітиви та об’єкти, == проти ===, truthy/falsy, особливості typeof, NaN, копіювання за посиланням і за значенням.
Модулі та сучасний синтаксис
ES-модулі проти CommonJS, деструктуризація, spread, optional chaining, ??, а також нові API: structuredClone, toSorted, Object.groupBy, методи Set.
Пам’ять і збирач сміття
GC на основі досяжності, типові витоки в довгоживучих застосунках (слухачі, таймери, відʼєднані DOM-вузли, кеші), коли допомагають WeakMap і WeakRef.
DOM і браузерні API
Спливання подій і делегування, fetch з AbortController, варіанти сховищ і як не блокувати головний потік.
Питання на співбесіді JavaScript за рівнями
Junior
Чим відрізняються var, let і const?
Що має бути в сильній відповіді:var має функціональну область видимості й піднімається зі значенням undefined, а let і const — блочні та до рядка оголошення перебувають у temporal dead zone, тож ранній доступ кидає ReferenceError. const забороняє перепризначення змінної, а не зміну вмісту: об’єкт чи масив у const можна мутувати. Сильна відповідь згадує, що let виправляє баг із замиканням у циклі, бо кожна ітерація отримує нову змінну.
У чому різниця між == і ===?
Що має бути в сильній відповіді:=== порівнює без приведення типів, а == спершу застосовує правила coercion, звідси сюрпризи на кшталт 0 == "" → true. Варто назвати корисний виняток: null == undefined дає true, тому x == null перевіряє обидва значення, а NaN не дорівнює нічому, навіть собі (для перевірки — Number.isNaN). За замовчуванням — ===, а == null лише свідомо.
Що таке замикання? Наведіть практичний приклад.
Що має бути в сильній відповіді:Замикання — це функція разом із лексичним оточенням, у якому її створено, тож вона читає й змінює зовнішні змінні навіть після завершення зовнішньої функції. Практика: приватний стан (лічильник, кеш для memoize), фабрики функцій, обробники подій, що пам’ятають налаштування. Добре також сказати про ціну: замикання утримує захоплені об’єкти, і це може спричинити витік пам’яті.
Що повертає typeof null і як перевірити, що значення — масив?
Що має бути в сильній відповіді:typeof null повертає 'object' — історичний баг, який лишили заради сумісності, тому null перевіряють явно через === null. Для масиву typeof теж дає 'object', тож використовують Array.isArray(value), який, на відміну від instanceof Array, працює і між iframe. Бонус: typeof функції — 'function', а typeof неоголошеної змінної повертає 'undefined' без помилки.
Що таке делегування подій і навіщо воно?
Що має бути в сильній відповіді:Більшість DOM-подій спливають від цільового елемента вгору по предках, тож можна повісити один слухач на батька й через event.target (часто з closest()) визначити, по якому дочірньому елементу клікнули. Це економить пам’ять, працює для елементів, доданих пізніше, і спрощує прибирання. Варто згадати, що focus не спливає (є focusin), і різницю між stopPropagation та preventDefault.
Middle
Що виведе код і чому: console.log(1); setTimeout(() => console.log(2), 0); Promise.resolve().then(() => console.log(3)); console.log(4);
Що має бути в сильній відповіді:Виведе 1, 4, 3, 2. Спершу виконується синхронний код; колбек .then потрапляє в чергу мікрозадач, а setTimeout — у чергу задач (макрозадач). Коли поточний скрипт завершився, event loop повністю спорожнює мікрозадачі й лише потім бере наступну задачу, тому 3 виводиться раніше за 2 навіть із затримкою 0 мс.
Як визначається значення this?
Що має бути в сильній відповіді:Для звичайних функцій this залежить від способу виклику: new прив’язує новий об’єкт, call/apply/bind задають його явно, obj.method() дає obj, а простий виклик — undefined у strict mode (globalThis у нестрогому). Стрілкові функції не мають власного this і беруть його із зовнішньої області. Типовий баг — передати obj.method як колбек і втратити this; лікується bind або обгорткою-стрілкою.
Порівняйте Promise.all, Promise.allSettled, Promise.race і Promise.any.
Що має бути в сильній відповіді:all повертає всі значення в порядку вхідних промісів і відхиляється на першій помилці; allSettled чекає всіх і повертає об’єкти зі статусом, ніколи не відхиляючись. race завершується разом із першим завершеним промісом, хоч успіхом, хоч помилкою; any бере перший успішний і відхиляється з AggregateError, лише якщо впали всі. Жоден із них не скасовує решту роботи — для цього потрібен AbortController.
Як класи в JavaScript пов’язані з прототипами?
Що має бути в сильній відповіді:class здебільшого синтаксис над функціями-конструкторами: методи лежать у Class.prototype, а екземпляри знаходять їх через ланцюжок [[Prototype]]; extends зв’язує і прототипи, і самі конструктори. Відмінності від звичайних функцій: тіло класу завжди в strict mode, клас можна викликати лише з new, а оголошення перебуває в TDZ до виконання. Справжні приватні поля (#field) і static-блоки — це вже не просто цукор, а можливості лише класів.
Debounce проти throttle: у чому різниця і як реалізувати debounce?
Що має бути в сильній відповіді:Debounce викликає функцію лише після того, як виклики припинились на N мс (пошук під час введення, кінець resize); throttle — не частіше ніж раз на N мс (scroll, mousemove). Debounce — це замикання з id таймера: на кожен виклик скидаємо попередній timeout і ставимо новий, який викличе оригінальну функцію з останніми аргументами та this. Плюс — згадати опції leading/trailing і скасування відкладеного виклику при демонтажі.
Senior
Як знайти й виправити витік пам’яті в SPA, що працює годинами?
Що має бути в сильній відповіді:GC звільняє лише недосяжні об’єкти, тож витік — це те, на що помилково лишилося посилання: незняті слухачі й таймери, замикання з великими даними, відʼєднані DOM-вузли у змінних, необмежені кеші чи глобальні стори. Діагностика: heap snapshots у DevTools до і після повторюваної дії, порівняння утримуваних об’єктів і їхніх retainer-ланцюжків. Виправлення: знімати слухачі при демонтажі (сигнал AbortController знімає їх пачкою), обмежувати кеші, для метаданих за ключем-об’єктом брати WeakMap.
Які практичні відмінності між ES-модулями та CommonJS?
Що має бути в сильній відповіді:Імпорти ESM статичні й резолвляться до виконання, що дає tree shaking, top-level await і живі прив’язки до експортів; require у CommonJS — синхронний виклик під час виконання, що повертає об’єкт module.exports. ESM завжди в strict mode і замість __dirname використовує import.meta. Щодо сумісності: актуальні версії Node вміють require() синхронних ES-модулів, а модулі з top-level await досі потребують import().
Важке обчислення підвішує інтерфейс. Як зберегти чуйність сторінки?
Що має бути в сильній відповіді:JavaScript виконується в головному потоці, а браузер рендерить і обробляє введення лише між задачами, тому довгі задачі псують чуйність та INP. Варіанти: розбити роботу на шматки й віддавати керування event loop (scheduler.yield() там, де підтримується, інакше setTimeout чи MessageChannel), винести важкі обчислення у Web Worker, групувати читання й запис DOM, щоб уникнути layout thrashing. Спершу виміряти — у вкладці Performance або через Long Animation Frames API.
Які типові пастки async/await у продакшн-коді?
Що має бути в сильній відповіді:Якщо await’ити незалежні виклики по черзі, вони стають послідовними — краще запустити разом і чекати через Promise.all. Пропущений await або «загублений» проміс означає, що try/catch не побачить помилку, і буде unhandled rejection. Array.forEach не чекає async-колбеків: для послідовного виконання — for...of, для паралельного — map плюс Promise.all; і пам’ятати, що кожен await продовжується в мікрозадачі, тобто пізніше, ніж здається з коду.
Як реалізувати скасування й уникнути race condition в асинхронних UI-сценаріях?
Що має бути в сильній відповіді:Через AbortController: передавати signal у fetch і власні async-функції та скасовувати попередній запит, коли стартує новий (наприклад, пошук під час введення), щоб застаріла відповідь не перезаписала свіжу. AbortSignal.timeout() додає дедлайн, AbortSignal.any() об’єднує сигнали. Варто сказати, що скасування відхиляє проміс з AbortError, який треба обробляти окремо від справжніх помилок, і що той самий signal знімає слухачі подій.
Як проходить мок-співбесіда з JavaScript
- Оберіть JavaScript (та інші технології зі свого стеку), свій рівень і мову співбесіди: українську, англійську або російську. Або завантажте резюме й опис вакансії.
- Відповідайте на кожне запитання голосом, як на справжній співбесіді.
- Отримайте оцінку кожної відповіді за точністю, повнотою та зрозумілістю і звіт зі слабкими місцями.
Як відповідати на питання з JavaScript уголос
- →Тримайтеся структури: визначення одним реченням, як це працює всередині, короткий приклад. На «що таке замикання» — секунд 30, а не три хвилини.
- →У задачах «що виведе код» проговорюйте виконання: спочатку синхронний код, потім мікрозадачі, потім наступна задача. Фінальний порядок назвіть окремо й чітко.
- →Код уголос читається погано, тому описуйте його словами: «стрілкова функція, що повертає проміс» краще, ніж диктувати дужки й крапки з комою.
- →Називайте крайні випадки до того, як спитають: NaN, null проти undefined, strict mode, this у стрілкових функціях. Саме це відрізняє повну відповідь від просто правильної.
- →Підкріплюйте теорію реальним випадком: втрачений this у колбеку, витік через незнятий слухач. Коротка історія з досвіду особливо важлива на middle і senior.
Часті запитання
Чи треба писати код на JavaScript співбесіді тут?
Ні. Редактора для live coding немає: питання усні й концептуальні, відповідаєте голосом. Вас можуть попросити передбачити результат фрагмента коду, пояснити, як би ви реалізували debounce, або розповісти, як шукали б баг.
Можна потренувати TypeScript?
Так, TypeScript можна обрати як окрему технологію. Трек JavaScript зосереджений на самій мові та середовищі виконання: області видимості, this, event loop, асинхронний код, пам’ять і браузерні API.
Чи підійде це досвідченим розробникам?
Оберіть рівень senior або завантажте вакансію — питання зміщуються до архітектури асинхронного коду, продуктивності, витоків пам’яті й модульних систем. Звіт оцінює кожну відповідь за технічною точністю, повнотою та ясністю, тож видно, де пояснення «просідають».
Скільки це коштує?
Перша співбесіда (до 5 питань) безкоштовна. Далі — оплата за кожну співбесіду, від $1.75, без підписки.