Перейти к содержимому
Тема 8 из 16
Теория

Стрелочные функции и замыкания

Зачем это нужно

В JavaScript функция — это значение, такое же, как число или строка. Её можно положить в переменную, передать в другую функцию, вернуть из функции. На этом построено очень многое: обработчики кликов, методы массивов map и filter (следующие темы), таймеры, запросы к серверу. А короткая стрелочная запись делает такой код компактным и читаемым.

Функциональное выражение

Функцию можно создать и положить в переменную:

const greet = function (name) {
  return `Привет, ${name}!`;
};
console.log(greet("Аня"));

Вывод:

Привет, Аня!

Это функциональное выражение. Отличие от объявления function greet() {} — его можно вызвать только после строки, где оно создано.

Стрелочные функции

Та же функция короче:

const greet = (name) => {
  return `Привет, ${name}!`;
};

А если тело — одно выражение, фигурные скобки и return можно убрать: результат вернётся сам.

const greet = (name) => `Привет, ${name}!`;
const add = (a, b) => a + b;
const random = () => Math.random();   // без параметров — пустые скобки
const square = n => n * n;            // один параметр — скобки можно опустить

console.log(add(2, 3), square(5));

Вывод:

5 25

Осторожно с объектами: чтобы вернуть объект в короткой форме, его берут в круглые скобки — () => ({ ok: true }). Иначе фигурные скобки примут за тело функции.

Функции как аргументы: колбэки

Функцию, которую передают в другую функцию, чтобы та её вызвала, называют колбэком (callback — «перезвони»):

function repeat(times, action) {
  for (let i = 1; i <= times; i++) {
    action(i);
  }
}

repeat(3, (n) => console.log("Повтор №" + n));

Вывод:

Повтор №1
Повтор №2
Повтор №3

Функция repeat не знает, что делать, — она знает только сколько раз. А что делать, решает тот, кто её вызывает. Так устроены setTimeout(колбэк, мс), addEventListener("click", колбэк) и методы массивов.

Функции, которые возвращают функции

function multiplier(k) {
  return (n) => n * k;
}

const triple = multiplier(3);
const tenTimes = multiplier(10);
console.log(triple(5), tenTimes(5));

Вывод:

15 50

multiplier — «фабрика» функций: каждый вызов создаёт новую функцию со своим k.

Замыкания

Обрати внимание: triple вызывается после того, как multiplier уже закончила работу. Откуда она помнит k = 3? Функция в JavaScript запоминает переменные того места, где её создали. Это называется замыкание (closure).

function makeGreeter(greeting) {
  let calls = 0;
  return (name) => {
    calls++;
    return `${greeting}, ${name}! (раз ${calls})`;
  };
}

const hi = makeGreeter("Привет");
console.log(hi("Аня"));
console.log(hi("Тимур"));

Вывод:

Привет, Аня! (раз 1)
Привет, Тимур! (раз 2)

Переменная calls живёт, пока жива функция hi, и при этом спрятана: снаружи её не изменить. Так в JS делают «приватные» данные.

Как это работает внутри

Каждый вызов функции создаёт окружение — набор её переменных. Обычно после выхода из функции окружение выбрасывается. Но если внутри создали другую функцию и вернули её наружу, та хранит ссылку на окружение, и оно продолжает жить. Каждый новый вызов makeCounter() создаёт новое окружение — поэтому два счётчика не мешают друг другу.

У стрелочных функций нет своего this и prototype — поэтому их не используют как конструкторы и как методы объектов, которым нужен this (об этом — в теме про объекты).

Частые ошибки

  1. Фигурные скобки без return. (n) => { n * 2 } возвращает undefined. Либо убери скобки, либо допиши return.
  2. Вызов вместо передачи. repeat(3, sayHi()) передаёт результат вызова. Нужно repeat(3, sayHi).
  3. Объект без скобок. () => { a: 1 } — это тело функции, а не объект. Нужно () => ({ a: 1 }).
  4. Общая переменная вне фабрики. Если let count = 0 написать снаружи makeCounter, все счётчики будут делить одно число.
  5. Вызов выражения до создания. const f = … нельзя вызвать выше этой строки.

Шпаргалка

Что Как
Выражение const f = function (x) { return x; };
Стрелка с телом const f = (x) => { return x * 2; };
Короткая стрелка const f = (x) => x * 2;
Без параметров () => 42
Вернуть объект () => ({ ok: true })
Колбэк repeat(3, (i) => console.log(i))
Замыкание функция помнит переменные места, где создана

Стрелка

Лёгкая+10 XP

Создай константу double — стрелочную функцию, которая возвращает число, умноженное на 2.

double(4)   → 8
double(-5)  → -10

Подключи коннектор, чтобы решать задачи

Код задач выполняется на твоём компьютере — так быстрее и надёжнее, чем в браузере. Для этого нужна бесплатная программа-коннектор CodeWithMe. Подключить её нужно один раз.

Ищем коннектор на этом компьютере…

  1. 1
    Скачай коннектор для своей системы (Windows, macOS или Linux).Скачать коннекторНа странице загрузки выбери файл со своей системой в названии, например windows-amd64.
  2. 2Запусти его и выбери папку, где будут лежать твои решения. Python и Node.js он поставит туда сам, когда понадобится.
  3. 3
    Введи ниже код из 6 цифр — он написан в окне коннектора («Код для сайта CodeWithMe»). Если браузер спросит про доступ к локальной сети — разреши.

Коннектор открытый (исходный код на GitHub), работает только на твоём компьютере и выполняет код лишь после ввода кода сопряжения.