Callback в методах массивов JavaScript

Многие методы массивов принимают функцию. Эта функция вызывается для элементов массива и называется callback-функцией.

let numbers = [1, 2, 3];

let result = numbers.map((number) => number * 2);

console.log(result); // [2, 4, 6]

В примере callback - это стрелочная функция (number) => number * 2. Метод map() вызывает ее для каждого элемента массива.

Что такое callback в методах массивов

Callback в методах массивов - это функция, которую мы передаем в метод, чтобы описать действие для одного элемента.

let names = ['Анна', 'Олег', 'Мария'];

names.forEach((name) => {
  console.log(name);
});

Мы не пишем цикл вручную. Метод forEach() сам проходит по массиву и на каждом шаге вызывает переданную функцию.

Кто вызывает callback

Callback вызывает не разработчик напрямую, а сам метод массива.

let numbers = [10, 20, 30];

numbers.forEach((number) => {
  console.log(number);
});

Запись выше можно читать так: для каждого элемента массива numbers вызови функцию и передай в нее текущий элемент.

Поэтому callback обычно передают без круглых скобок вызова.

numbers.forEach((number) => {
  console.log(number);
});

Метод сам решает, сколько раз вызвать функцию и какие значения в нее передать.

Параметры callback-функции

У большинства методов массивов callback может принимать три параметра:

array.method((element, index, array) => {
  // код
});

element - текущий элемент.

index - индекс текущего элемента.

array - массив, который перебирается.

Названия параметров можно менять. Важен порядок.

Текущий элемент

Первый параметр используется чаще всего. В него попадает очередной элемент массива.

let prices = [100, 200, 300];

let result = prices.map((price) => price + 50);

console.log(result); // [150, 250, 350]

На первом шаге price равен 100, на втором - 200, на третьем - 300.

Индекс элемента

Второй параметр нужен, когда важно знать позицию элемента в массиве.

let names = ['Анна', 'Олег', 'Мария'];

names.forEach((name, index) => {
  console.log(index + ': ' + name);
});

Результат:

0: Анна
1: Олег
2: Мария

Индекс также удобно использовать, когда нужно добавить номер к элементу.

let names = ['Анна', 'Олег', 'Мария'];

let numberedNames = names.map((name, index) => {
  return index + 1 + '. ' + name;
});

console.log(numberedNames);

Сам массив

Третий параметр - это массив, по которому идет перебор.

let numbers = [10, 20, 30];

numbers.forEach((number, index, array) => {
  console.log(number, array.length);
});

На практике третий параметр нужен не так часто. Если массив уже доступен из внешней переменной, обычно проще использовать ее.

Зачем нужен return

В разных методах результат callback-функции используется по-разному.

В map() значение после return становится элементом нового массива.

let numbers = [1, 2, 3];

let doubled = numbers.map((number) => {
  return number * 2;
});

console.log(doubled); // [2, 4, 6]

В filter() callback должен вернуть true или false. Если вернулся true, элемент остается в новом массиве.

let numbers = [1, 2, 3, 4];

let even = numbers.filter((number) => {
  return number % 2 === 0;
});

console.log(even); // [2, 4]

В some() и every() результат callback тоже используется как проверка.

let ages = [18, 24, 31];

let hasAdult = ages.some((age) => {
  return age >= 18;
});

console.log(hasAdult); // true

В forEach() результат callback-функции игнорируется. Метод просто выполняет действие для каждого элемента.

let numbers = [1, 2, 3];

let result = numbers.forEach((number) => {
  return number * 2;
});

console.log(result); // undefined

Именованная функция

Callback не обязательно писать прямо внутри метода. Функцию можно вынести отдельно.

let numbers = [1, 2, 3];

function double(number) {
  return number * 2;
}

let result = numbers.map(double);

console.log(result); // [2, 4, 6]

Обратите внимание, что в map() передается double, а не double(). Скобки вызвали бы функцию сразу, а нам нужно передать саму функцию.

Callback в reduce()

У reduce() callback немного отличается. Первым параметром идет накопленное значение, вторым - текущий элемент.

let numbers = [10, 20, 30];

let sum = numbers.reduce((total, number) => {
  return total + number;
}, 0);

console.log(sum); // 60

total хранит промежуточный результат. number - текущий элемент массива. Значение 0 в конце задает начальное значение для total.

У reduce() также можно получить индекс и массив, но в начале обучения чаще достаточно понимать первые два параметра.

Итого

1. Callback в методах массивов - это функция, которую метод вызывает для элементов массива.

2. Обычно callback получает текущий элемент, индекс и сам массив.

3. В map(), filter(), some() и every() важно, что возвращает callback.

4. В forEach() возвращаемое значение не используется.

5. В reduce() первым параметром callback-функции идет накопленное значение.