Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Замыкания

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

Функция внутри функции

Функцию можно объявить внутри другой функции и вернуть через return, как любое значение:

function makeGreeter() {
  return () => 'Привет!';
}
 
const greet = makeGreeter();
 
console.log(greet()); // Привет!

makeGreeter() возвращает функцию, мы сохраняем её в greet и вызываем уже её.

Функция помнит внешние переменные

Внутренняя функция видит переменные внешней — это мы знаем из урока об области видимости. Удивительно другое: она видит их и после того, как внешняя функция завершилась:

function makeGreeter(name) {
  return () => `Привет, ${name}!`;
}
 
const greetAnna = makeGreeter('Анна');
 
console.log(greetAnna()); // Привет, Анна!

Вызов makeGreeter('Анна') давно закончился, но возвращённая функция всё ещё помнит name. Это и есть замыкание.

Счётчик

Замыкание может не только читать запомненную переменную, но и менять её. Так получается счётчик, который хранит своё состояние между вызовами:

function makeCounter() {
  let count = 0;
  return () => {
    count++;
    return count;
  };
}
 
const counter = makeCounter();
 
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

Переменная count живёт, пока существует функция counter.

У каждого вызова своё окружение

Каждый вызов внешней функции создаёт новый набор переменных. Поэтому два счётчика не мешают друг другу:

function makeCounter() {
  let count = 0;
  return () => ++count;
}
 
const a = makeCounter();
const b = makeCounter();
 
a();
a();
 
console.log(a()); // 3
console.log(b()); // 1

Фабрика функций

Функцию, которая создаёт и возвращает другие функции, называют фабрикой. Она избавляет от повторов, когда нужно несколько похожих функций с разными настройками:

function makeMultiplier(factor) {
  return (n) => n * factor;
}
 
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
 
console.log(double(5)); // 10
console.log(triple(5)); // 15

Скрытые данные

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

Частая ошибка

Каждый вызов makeCounter() создаёт новый счётчик с нулём. Если вызывать внешнюю функцию каждый раз заново, счёт не накапливается:

function makeCounter() {
  let count = 0;
  return () => ++count;
}
 
console.log(makeCounter()()); // 1
console.log(makeCounter()()); // 1

Создайте счётчик один раз, сохраните его в переменную и вызывайте уже её: const counter = makeCounter();.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.