Oboe
No history yet

помоги подготовиться к этой вакансии https://hh.ru/vacancy/135745206?query=frontend+javascript&hhtmFrom=vacancy_search_list

Привет! Отличная вакансия: разработка единого интерфейса и бэкенд-обвязки для ИИ-агента в СберМаркетинге — это очень актуальное и технологичное направление. Чтобы наша подготовка была максимально точечной и эффективной, давай сначала определим твою стартовую точку.

Пришли, пожалуйста, ключевые требования и стек из описания этой вакансии (или просто скопируй её текст, если под рукой нет файла), а также расскажи немного о своем текущем опыте (Junior/Middle/Senior) — с какими технологиями из стека JS/React/Node.js ты работаешь чаще всего?

Код под давлением: как пройти собеседование на Frontend/Fullstack разработчикаPodcast

Я Junior, хочу подтянуть базу JS/React и понять требования вакансии

Отличный выбор! Поскольку ты начинаешь свой путь как Junior, крепкая база — это твой главный козырь на собеседовании. Давай сразу посмотрим на карту нашего обучения, чтобы понимать, как мы придем к твоей цели.

Your path
React и управление состоянием
TypeScript и типизация приложений
Архитектура frontend, сборка и производительность
Собеседование: Live Coding и алгоритмы

Мы начнем с самого фундамента. На собеседовании в СберМаркетинг никто не поверит в твое знание React, если ты будешь путаться в базовых механизмах самого языка.

Давай начнем с концепции, без которой невозможно представить современный JavaScript — это область видимости и . На интервью любят давать каверзные вопросы на эту тему, проверяя, понимает ли разработчик, где именно в памяти хранятся его переменные.

Представь замыкание на простом примере. У нас есть функция, которая создает счетчик. Каждый раз, когда мы ее вызываем, она возвращает новую функцию. Эта внутренняя функция «помнит» переменную count, хотя внешняя функция уже завершила свою работу.

function createCounter() {
  let count = 0; // Переменная в родительской области
  
  return function() {
    count++;
    return count;
  };
}

const counter1 = createCounter();
console.log(counter1()); // 1
console.log(counter1()); // 2

Давай проверим, как эта теория укладывается на практике. На собеседованиях часто дают классическую задачку с циклом и асинхронным выводом.

Посмотри на код ниже. Что выведет этот код в консоль при запуске?

for (var i = 0; i < 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, 1000);
}

Три раза число 2 через секунду

На самом деле код выведет в консоль три раза число 3, причем ровно через одну секунду.

Понимаю, почему ты выбрал число 2 — кажется логичным, что на последней итерации цикла i было равно двум. Но давай разберем эту классическую ловушку по шагам, чтобы на реальном собеседовании в СберМаркетинг ты легко щелкал такие задачи.

Разбор полетов: почему тройка?

В коде используется ключевое слово var для объявления переменной . У var отсутствует блочная область видимости — она ограничивается всей функцией (или глобальным окружением). Это означает, что для всего цикла создается одна-единственная переменная i в памяти.

Давай разложим выполнение по шагам:

  1. Цикл запускается и создает три асинхронных таймера setTimeout. Они отправляются в очередь ожидания.
  2. Сам цикл продолжает выполняться мгновенно. i последовательно принимает значения 0, 1, 2, а на выходе из цикла увеличивается до 3 (так как условие i < 3 перестает выполняться).
  3. Спустя секунду срабатывают таймеры. Функции внутри setTimeout начинают выполняться и обращаются к переменной i по ссылке из своего замыкания.
  4. Поскольку переменная i одна на всех, таймеры видят ее финальное актуальное значение на момент своего запуска. А оно к этому моменту уже равно 3.

A side-by-side memory binding comparison of var and let in a three-iteration loop with setTimeout.

Я подготовил небольшую визуализацию, чтобы наглядно показать, как три колбэка ссылаются на одну и ту же ячейку памяти с тройкой при использовании var.

Теперь, когда мы наглядно увидели коварство старого доброго var, давай разберемся, как исправить эту проблему с помощью современного стандарта JavaScript. Для этого достаточно лишь заменить одно ключевое слово.

дай ссылку на подкаст по подготовке к вакансии

Конечно! Я с удовольствием подготовил для тебя этот выпуск. Он поможет разложить по полочкам сложные темы перед собеседованием.

Один день до оффера: разбор конкретной вакансии Frontend/Fullstack разработчикаPodcast

Я обновил параметры генерации подкаста, ориентируясь на твой запрос. Аудио уже формируется — в нем подробно и простым языком разбираются ключевые ловушки, включая ту самую задачу с var и setTimeout, а также требования к Fullstack-разработчикам в СберМаркетинге.

Пока подкаст готовится, давай закроем вопрос с областями видимости. Как ты думаешь, почему замена var на let в нашем цикле полностью решает проблему с выводом?

Потому что let создает свою переменную для каждой итерации

Абсолютно верно! Ты попал прямо в яблочко. Именно ключевое слово let (как и const) спасает нас от этой головной боли, создавая новую для каждой отдельной итерации цикла.

Как работает let под капотом

Когда мы пишем let i = 0 в заголовке цикла for, движок JavaScript делает потрясающую вещь. Вместо создания одной переменной на весь цикл, он при каждом шаге (итерации) создает совершенно новое лексическое окружение.

В это новое окружение копируется текущее значение i из предыдущего шага. Получается, что каждый из трех наших таймеров ссылается на свою персональную, неизменяемую в будущем переменную i, в которой бережно хранится 0, 1 или 2.

Давай посмотрим на практике, какими еще способами (помимо let) можно было решить эту задачу раньше. На реальном собеседовании в СберМаркетинг интервьюер может спросить: «А как бы вы решили эту проблему в старых стандартах JS, если бы let не существовал?»

Для этого традиционно использовались — немедленно вызываемые функции, которые создавали отдельную область видимости для каждой итерации, принудительно «запирая» текущее значение переменной внутри себя.

// Решение через IIFE для старых браузеров
for (var i = 0; i < 3; i++) {
  (function(localI) {
    setTimeout(function() {
      console.log(localI);
    }, 1000);
  })(i); // Передаем текущее значение i
}

Мы передаем текущее значение i в качестве аргумента localI. Внутри функции создается собственная область видимости, где значение localI уже никто не может изменить извне. В итоге мы получаем ожидаемые 0, 1, 2.

Теперь, когда мы окончательно разобрались с областями видимости и замыканиями, мы можем двигаться дальше по нашей карте подготовки к теме контекста вызова функции. Это одна из самых «горячих» тем на собеседованиях любого уровня.