JavaScript
Для чего модуль
Собрать не «набор фактов про язык», а рабочую инженерную модель JavaScript: как код реально выполняется, где чаще всего рождаются баги, и как это объяснять на собеседовании и в команде.
Результат после прохождения
- Вы объясняете поведение JS-кода через execution model, а не через заученные исключения.
- Вы уверенно разбираете async-сценарии: порядок выполнения, отмену, гонки, деградацию.
- Вы выбираете структуру данных и стиль преобразований с учетом читаемости и стоимости операций.
- Вы умеете довести «плавающий баг» до воспроизводимости и root cause.
Термины и аббревиатуры
| Термин | Коротко |
|---|---|
TDZ | Временная мертвая зона |
Closure | Функция + внешнее окружение |
Microtask | Приоритетная очередь задач |
Event Loop | Модель выполнения задач |
Prototype | Механизм наследования |
Фокус по грейдам
Junior: понимать базовые механики и объяснять их простыми примерами.Middle: применять тему в продуктовых сценариях с учетом рисков и ограничений.Senior: управлять архитектурными trade-offs, метриками и эволюцией решения.
Как работать с модулем
- Каждый урок п роходите в связке: теория -> код в консоли/песочнице -> разбор реального кейса.
- Для каждой темы фиксируйте два артефакта: краткое объяснение на 40-60 секунд и мини-кейс «где это ломалось/могло сломаться».
- После урока закрывайте минимум 3 вопроса из банка по этой теме.
Программа модуля
Урок 1. База языка
Цель: закрыть фундаментальные вопросы, на которых сыпятся даже сильные кандидаты.
Каркас мышления
Перед разбором любого куска JS задавайте 4 вопроса:
- Какие здесь типы и как они сравниваются?
- В какой области видимости живут переменные?
- Какое значение
thisв точке вызова? - Как будет найдено свойство: own property или по prototype chain?
Типы и сравнения без магии
В JS важно разделять:
- Primitive values (
string,number,bigint,boolean,null,undefined,symbol). - Objects (включая функции, массивы, даты, map/set).
- Reference equality vs value equality.
console.log(0 === false); // false
console.log(0 == false); // true (coercion)
console.log([] === []); // false (разные ссылки)
const a = { x: 1 };
const b = a;
console.log(a === b); // true
Практическое пра вило:
в продуктовой логике избегайте неявных сравнений (==) кроме явно понятных кейсов.
Hoisting, scope, TDZ
var hoist-ится с undefined, let/const hoist-ятся в TDZ.
function demo() {
console.log(a); // undefined
// console.log(b); // ReferenceError
var a = 1;
let b = 2;
}
Прод-следствие:
баги из-за случайного var часто выглядят как «иногда undefined в неожиданный момент».
this и prototype chain
this определяется местом вызова, а не местом объявления функции (кроме arrow-function).
const user = {
name: 'Ira',
regular() { return this.name; },
arrow: () => this?.name,
};
console.log(user.regular()); // "Ira"
console.log(user.arrow()); // undefined в strict mode окружении модуля
Prototype chain отвечает за lookup свойств, а не за копирование: это важно при полиморфизме и при дебаге «почему свойство есть в объекте, но не в own keys».
Где ломается в проде
- Случайная мутация объекта из shared state.
- Неверный
thisв callback/handler. - Логика на
==, которая проходит тесты и ломается на edge-case данных.
Мини-задача (обязательная)
Подготовьте 5 объяснений по 40-60 секунд:
var/let/const, ==/===, null/undefined, this, prototype chain.
Для каждого объяснения добавьте один реальный баг-кейс (или правдоподобный сценарий).
Что спросит интервьюер:
почему const не делает объект полностью immutable и где это ломает state в UI.
Критерий готовности по уроку: вы можете предсказать поведение 10 коротких фрагментов кода и объяснить каждое поведение через модель языка.
Урок 2. Асинхронность и runtime
Цель: уметь предсказуемо объяснять порядок выполнения и защищаться от async-багов.
Event Loop: минимальная рабочая модель
- Сначала выполняется sync-код.
- Потом дренируются microtasks (
Promise.then,queueMicrotask). - Потом берется следующая macrotask (
setTimeout, I/O callbacks).
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
// A, D, C, B
Promise combinators и выбор по задаче
Promise.all- «все или ошибка», быстрый fail.Promise.allSettled- «получить статус каждого».Promise.race- «первый завершившийся».Promise.any- «первый успешный», иначе AggregateError.
Cancellation и stale-response
Одна из самых частых причин «UI показывает старые данные»: старый запрос завершается позже нового и перетирает state.
let currentController;
async function loadUsers(query) {
currentController?.abort();
currentController = new AbortController();
const res = await fetch(`/api/users?q=${encodeURIComponent(query)}`, {
signal: currentController.signal,
});
return res.json();
}
Где ломается в проде
- «Проглоченные» ошибки в async-цепочке.
- Retry без лимита попыток.
- Неправильная обработка
abort, когда отмена считается «настоящей ошибкой».
Мини-задача (обязательная)
Разберите 5 фрагментов с setTimeout, Promise, async/await:
предскажите порядок логов и объясните, почему именно так.
Отдельно реализуйте fetch с timeout + cancel.
Что спросит интервьюер: как вы предотвращаете гонки запросов при быстром переключении фильтров в UI.
Критерий готовности по уроку: вы можете объяснить порядок выполнения кода и показать рабочую защиту от race-condition в UI/сервисе.
Урок 3. Структуры данных и функциональные подходы
Цель: писать предсказуемый и поддерживаемый код для коллекций и трансформаций.
Выбор структуры данных
Array- упорядоченные коллекции, удобно для трансформаций и рендера.Map- быстрый lookup по ключу и сохранение insertion order.Set- уникальность значений без ручной дедупликации.- Plain object - хорошо для сериализации, но не всегда лучший выбор для динамического словаря.
Чистые функции и контролируемые side effects
Чистая функция: при одинаковых входах всегда одинаковый выход и нет побочных эффектов. Это резко упрощает тестирование и рефакторинг.
function aggregateOrders(orders) {
return orders.reduce(
(acc, order) => {
const total = order.items.reduce((s, i) => s + i.price * i.qty, 0);
acc.count += 1;
acc.revenue += total;
return acc;
},
{ count: 0, revenue: 0 }
);
}
Иммутабельность: shallow vs deep
{ ...obj } копирует только первый уровень.
Если внутри вложенный объект/массив, ссылка сохраняется.
Где это ломается:
- Redux-like state обновляется «как будто immutable», но вложенность мутируется.
memo/shouldComponentUpdateне срабатывают корректно.
Readability vs cleverness
reduce полезен, когда реально есть аккумуляция.
Если логика читается хуже, выбирайте map + filter и промежуточные имена.
Мини-задача (обязательная)
Реализуйте преобразование списка заказов в агрегированную статистику без мутации входа. Добавьте тест на edge-cases: пустой список, заказ без items, невалидная цена.
Что спросит интервьюер:
почему иногда reduce хуже читается, чем комбинация map + filter.
Критерий готовности по уроку: вы выбираете структуру данных осознанно и можете объяснить сложность и читаемость выбранного решения.
Урок 4. Прод-кейсы и дебаг
Цель: перейти от «знаю теорию» к «могу разобрать инцидент».
Runbook: stale data после фильтрации
Пошаговый шаблон:
- Зафиксировать сценарий воспроизведения (какие клики, какой интервал, какие фильтры).
- Снять network timeline и убедиться, что ответы приходят в другом порядке.
- Проверить логику обновления state:
есть ли guard по
requestId/AbortController. - Проверить, нет ли двойного запроса из-за эффекта/ре-рендера.
- Добавить временное логирование
requestId -> response -> state update. - Зафиксировать fix и добавить regression test.
Инструменты, которые должны быть «под рукой»
- Breakpoints + conditional breakpoints.
- Network tab и сортировка по start/end time.
- Performance markers (
performance.mark/measure) для ключевых операций. - Structured logs в консоли для сложных async-цепочек.
Что отличает инженерный дебаг от хаотичного
- У вас есть гипотеза перед каждым действием.
- Каждый шаг уменьшает множество возможных причин.
- После фикса есть защита от повтора (тест, guard, мониторинг).
Мини-задача (обязательная)
Соберите runbook для бага: «иногда показываются устаревшие данные после фильтрации». Добавьте: признаки бага, шаги проверки, root cause, fix, проверку фикса.
Что спросит интервьюер: как вы доказываете, что проблема именно в async flow, а не в API.
Критерий готовности по уроку: вы можете довести плавающий баг до воспроизводимости, локализовать источник и доказать корректность исправления.
Практика
- Решите 12 задач: 8 из Junior JavaScript и 4 из Middle JavaScript и React.
- Напишите три утилиты:
debounce,throttle,fetchWithTimeoutAndAbort. - Реализуйте агрегатор заказов без мутаций + тесты на edge-cases.
- Подготовьте один debug-case: «stale data после фильтрации» с полным runbook.
- Отработайте спорные вопросы формулировок в Playbook ответов.
- Разберите один async-баг (гонка/устаревшие данные) в Песочнице и зафиксируйте фикс.
Связь с треками и вопросами
- Треки: Junior трек, Middle трек, Senior трек.
- Вопросы: Junior JavaScript, Middle JavaScript и React, Senior Frontend.
- Повторение: 3-5 вопросов без подсказок -> сверка с модулем -> повтор через 24 часа.