ForEach vs Map vs Reduce что и когда?

Столкнулась с тем что не понимаю когда применять метод map а когда forEach, так же постоянно встречаю reduce, но неясно почему выбирают его а не напрмер тот же map.

Кода следует использовать map, когда reduce, а когда forEach?

В чем их основное отличие?


Ответы (4 шт):

Автор решения: eri

FOREACH - когда у Вас "код-лапша", когда тело цикла простое - 2-5 строчек. Этот цикл легко читать.

А если код разбит на колбэки, в теле всё сложно и можно выделить это в одну функцию или там уже одна функция - то map,reduce.

MAP - применяет функцию к каждому элементу. на выходе массив той же длинны.

REDUCE - попарно берет свой результат на прошлой итерации и новый элемент из массива. На выходе одна переменная

→ Ссылка
Автор решения: vsemozhebuty

Если кратко:

  1. Когда нужно изменить текущий массив или использовать из него данные по очереди, не возвращая нового значения, лучше использовать forEach() (или цикл for-of). Пример: вывести все элементы массива в консоль по очереди.

  2. Когда нужно создать и вернуть новый массив, с тем же количеством элементов, но изменив их, лучше использовать map(). Пример: сделать из массива строк новый массив чисел.

  3. Когда нужно создать и вернуть совсем другое значение (примитив или объект), перебрав во время создания элементы массива, лучше использовать reduce(). Пример: вернуть сумму всех числовых элементов массива.

→ Ссылка
Автор решения: Vasily

Методы map, forEach, и reduce действительно имеют много общего, что и когда использовать зависит от того какой именно результат по итогу требуется получить.

Представим что у нас есть массив:

const locations = [
  {country: "Россия", population: 10},
  {country: "Китай", population: 100},
  {country: "США", population: 20}
]

Если нам нужно просто выполнить определенное действие для каждого элемента массива, то тут подойдет метод forEach:

locations.forEach(location => {
  console.log(location)
  // мы получим три вывода в консоль
  // по одному для каждой локации
  // {country: "Россия", population: 10}
  // {country: "Китай", population: 100}
  // {country: "США", population: 20}
})

// или так, если нам нужно только определенное значение

locations.forEach(location => {
  console.log(location.country)
  // Россия
  // Китай
  // США
})

// или так, по количеству значений в массиве 

locations.forEach(() => {
  console.log("Как дела?")
  // Как дела?
  // Как дела?
  // Как дела?
})

Если мы хотим трансформировать наш массив и занести результаты в переменную, то тут метод map будет более уместен чем forEach, поскольку первый по итогу сразу вернет новый массив.

Посмотрим на разницу forEach vs map в случае когда нам нужно "обернуть" каждое название страны в HTML таг:

// через forEach
const result = []
locations.forEach(location => {
  result.push(`<h1>${location.country}</h1>`)
})
console.log(result)
// ["<h1>Россия</h1>", "<h1>Китай</h1>", "<h1>США</h1>"]

// с использованием map
const result = locations.map(location => `<h1>${location.country}</h1>`)    
console.log(result)
// ["<h1>Россия</h1>", "<h1>Китай</h1>", "<h1>США</h1>"]

Метод reduce отличается от map тем что он возвращает финальное "значение".

Допустим мы хотим посчитать суммарный размер населения:

const result = locations.reduce((total, location) => {
  return total + location.population
}, 0)

console.log(result)
// 130

Это достаточно простой пример, но "финальным значением" может быть не только число, а, например, объект или массив, что делает метод reduce поистине мощным инструментом трансформаций.

→ Ссылка
Автор решения: OPTIMUS PRIME

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

► forEach (обычный перебор)

let arr = [1, 2, 3];

// --
for (let i = 0; i < arr.length; i++) {
  console.log( "for", arr[i] );
}

// --
arr.forEach( e => console.log("forEach", e) ); // e ←→ arr[i]

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

let arr = [1, 2, 3];

// --
let result = [];
for (let i = 0; i < arr.length; i++) {
  result.push( arr[i] * 2 );
}
console.log(result); // [2, 4, 6]

// --
console.log( arr.map( e => e * 2 ) ); // [2, 4, 6]

► reduce — можно использовать во всех случаях, где помимо основных параметров, нужна еще одна дополнительная переменная, которая будет что-то хранить в процессе перебора.

let arr = [1, 2, 3];

// --
let sum = 0;
for (let i = 0; i < arr.length; i++) {
  sum += arr[i];
}
console.log(sum); // 6

// --                                         ↓ Вместо let sum = 0;
console.log( arr.reduce( (sum, e) => sum + e, 0 ) ); // 6

// Вместо объявления переменной sum, её можно встроить в одну строчку с вызовом.
// Также вызывает функцию для каждого элемента.
// То, что вернет функция - станет значением sum при следующем вызове функции.

// В конце перебора вернет итоговое значение sum.


А "внутри" происходит примерно это:

Array.prototype.my_forEach = function(fn, context) {
  for (let i = 0; i < this.length; i++) {
    fn.call(context, arr[i], i, arr);
  } // Переданная функция получает "имя" fn, и вызывается через неё в цикле.
};

Array.prototype.my_map = function(fn, context) {
  let result = [];
  for (let i = 0; i < this.length; i++) {
    result.push( fn.call(context, arr[i], i, arr) );
  } // в будущий массив добавляются результаты вызовов функции.
  
  return result;
};

Array.prototype.my_reduce = function(fn, value) {
  let i = 0;
  
  if (typeof value == "undefined") {
    if (this.length == 0) {
      throw new Error("Reduce of empty array with no initial value");
    }
    
    i = 1;
    value = this[0];
    // Если второй аргумент (объявление начального значения) не указан,
    // берется первый элемент массива вместо него.
  }
  
  for (i; i < this.length; i++) {
    value = fn(value, arr[i], i, arr);
  }
  
  return value;
};

/***/

let arr = [1, 2, 3];

arr.my_forEach( e => console.log(e) ); // 1, 2, 3

console.log( arr.my_map( e => e * 2 ) ); // [2, 4, 6]

console.log( arr.my_reduce( (sum, e) => sum + e ) ); // 6
.as-console-wrapper { min-height: 100vh !important; }

→ Ссылка