Понимание различий между методами массива .forEach(), .map() и .filter() в JavaScript.

В JavaScript перебор массивов может быть вполне удовлетворительным. Есть что-то особенное в том, чтобы пролистывать длинные списки данных и иметь возможность манипулировать каждым элементом четко и организованно. Когда я впервые начал работать с методами цикла массива, а именно с .forEach(), .map() и .filter(), я обнаружил, что тонкости между ними сложны, и временами их различия приводили меня в замешательство. Это было неприятно, чтобы быть уверенным. Но после некоторой практики я понял, что важно обращать внимание на то, как методы возвращают (или не возвращают) значения. Как только вы поймете, как все возвращается, вы, наконец, сможете выйти на новые рубежи развития.

Чтобы было ясно, .forEach() не возвращает значение, в то время как .map() и .filter() возвращают значение. Это действительно важное различие. .forEach() будет просто жить сам по себе, в то время как .map() и .filter() обычно будут иметь свое новое значение массива, помещенное в переменную. Таким образом, вы увидите что-то вроде этого:

randomArray = [5, 7, 24, 45]
randomArray.forEach(() => {})
const mappedArray = randomArray.map(() => {})
const filteredArray = randomArray.filter() => {})

Однако с .forEach(), хотя новой переменной нет, значения массива по-прежнему обычно обрабатываются или помещаются в другое место; это просто не в новом массиве. Например, если вы посмотрите на функцию обратного вызова .forEach() ниже, вы увидите, что содержимое массива помещается в элементы списка в неупорядоченном списке в DOM.

const list = document.querySelector('ul');
randomArray.forEach((item) => {
  list.innerHTML += `<li>${item}</li>`
})

Таким образом, хотя .forEach() технически не возвращает значение, можно утверждать, что он устраняет посредника в уравнении; он просто быстро передает информацию кому-то еще, а затем исчезает в закате. Красиво и прямолинейно!

.map() и .filter(), с другой стороны, do возвращают значение. Это означает, что после того, как они сделали свою работу, родился новый массив. И это здорово, потому что они оба немного меняют данные, давая нам что-то новое для работы.

Однако небольшое различие между ними заключается в том, что .map() всегда будет возвращать массив одинаковой длины. Он может внести некоторые действительно серьезные изменения в то, как выглядят данные, но он всегда будет возвращать одно и то же количество элементов массива. Например, давайте умножим каждый элемент в randomArray на 6.

const arrayTimesSix = randomArray.map(() => {
  return item * 6
})

Теперь у нас есть новый массив с именем arrayTimesSix, и он был заполнен каждым элементом из предыдущего массива, но умноженным на шесть.

[5, 7, 24, 45] // randomArray
[30, 42, 144, 270] // arrayTimesSix

Здесь вы можете ясно видеть, что .map() вернул массив, и он имеет ту же длину, что и массив, который был зациклен. Теперь мы перейдем к .filter(), который предназначен для возврата подмножества массива на основе условия. Это как если бы у меня была куча грязной посуды в раковине, и я хотел бы просмотреть каждый предмет и просто взять, скажем, ложки, я мог бы сделать это с помощью фильтра. Но в мире JavaScript вы можете просто сказать, что число больше другого числа. Например, допустим, вам просто нужны числа больше 10.

const greaterThanTen = randomArray.filter((item) => {
  return item > 10
})

С помощью этого метода фильтрации нам будет предоставлен совершенно новый массив, но он будет выглядеть так.

[5, 7, 24, 45] // randomArray
[24, 45] // greaterThanTen

Вы увидите, что возвращенный массив меньше исходного, и это потому, что это сработало! Это отфильтровало! Если вы вернули массив той же длины, в чем смысл? Каждый элемент будет считаться истинным, и вы просто сделаете копию массива, верно? Запомним это на потом. 👀

Теперь давайте посмотрим на них с другой точки зрения. Что, если бы мы попытались использовать каждый из этих методов, но использовали различную логику внутри метода. Позволь мне объяснить. Здесь я создам метод .map(), но буду использовать логику .filter() внутри блока цикла.

const mapWithFilter = randomArray.map((item) => {
  return item > 10
})

Массив mapWithFilter будет выглядеть так:

[5, 7, 24, 45] // randomArray
[false, false, true, true] // mapWithFilter

Это .map(), поэтому массив имеет ту же длину, что и первый. Но поскольку мы задавали вопрос «больше ли это число 10?», массив полон истинных и ложных. Я не уверен, что это то, что вы хотели бы (или нуждались) когда-либо делать, но приятно подтвердить, что MO .map() всегда возвращает массив одинаковой длины.

Теперь сделаем обратное. Метод фильтра с логикой карты внутри.

const filterWithMap = randomArray.filter((item) => {
  return item * 6
})

Здесь мы собираемся вернуть каждый элемент, умноженный на шесть. И вот результат.

[5, 7, 24, 45] // randomArray
[5, 7, 24, 45] // filterWithMap

Это то же самое? И такой же длины? Это сбило меня с толку, когда я впервые попробовал это, но в конце концов я понял, что .filter() принимает только логические значения. Раньше он отвечал на вопрос: Это больше 10 футов? Но в данном случае все немного неясно. «Поскольку любое число, отличное от нуля, считается истинным в JavaScript, метод .filter() считывает каждый элемент как true, true, true, true, что на языке фильтров переводится как "сохранить все". Опять же, это совсем непрактично, но я нахожу это полезным для закрепления идеи о том, что каждый элемент, проходящий через .filter(), должен отвечать на один вопрос: это правда или ложь?.

Итак, у вас есть это! Три метода массива, каждый со своими небольшими отличиями и возможностями.

.forEach() ничего не возвращает, но щедро передает свои элементы другому элементу.

.map() всегда возвращает массив одинакового размера, независимо от того, сколько элементов было изменено.

.filter() может возвращать элемент только в зависимости от того, является ли он истинным или ложным.

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