Scope и замыкания

↑ 1.4 JavaScript: основы · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: junior

Зачем это на собесе

Замыкания — один из главных вопросов. Нужно объяснить, что такое лексическое окружение, и привести примеры применения.

Объяснение

Scope (область видимости): глобальный, функциональный, блочный, модульный. Лексическая область определяется местом объявления, а не вызова. Поиск переменной идёт по цепочке scope от внутреннего к внешнему.

Замыкание — функция вместе с ссылкой на лексическое окружение, в котором она создана. Функция «помнит» внешние переменные даже после завершения внешней функции.

function counter() {
  let count = 0;                      // приватное состояние
  return { inc: () => ++count, get: () => count };
}
const c = counter();
c.inc(); c.inc(); c.get();            // 2
 
// Фабрика функций
const multiplier = (k) => (x) => x * k;
const double = multiplier(2);
 
// Классическая ловушка
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));   // 3 3 3
for (let j = 0; j < 3; j++) setTimeout(() => console.log(j));   // 0 1 2
// в старом коде: (function (n) { setTimeout(() => console.log(n)); })(i);   // IIFE
 
// Мемоизация
const memo = (fn, cache = new Map()) => (x) => cache.has(x) ? cache.get(x) : (cache.set(x, fn(x)), cache.get(x));

Применения: приватные данные (модульный паттерн), каррирование и частичное применение, мемоизация, debounce/throttle, обработчики событий, коллбэки, once.

Нюансы и подводные камни

  • Замыкание удерживает всё окружение, а не только используемые переменные (движки оптимизируют, но не гарантируют): возможны утечки памяти при захвате больших объектов.
  • Обработчики событий и таймеры, захватившие DOM-узлы, не освобождают память до удаления.
  • Циклы с var и асинхронными коллбэками — типичная ошибка.
  • Функции в цикле создаются заново на каждой итерации: учитывайте стоимость.

Практика

  1. Реализуйте once(fn), memoize(fn), счётчик с приватным состоянием.
  2. Исправьте цикл с var тремя способами.
  3. Найдите замыкание, удерживающее лишнее, в профилировщике памяти.

Вопросы с ответами

Связанные темы