Мы все должны согласиться с тем, что JavaScript - это здорово! Но вы знаете, что? LEGO еще лучше! Почему? Потому что с помощью этой удивительной игрушки вы можете объяснить и смоделировать так много идей, моделей поведения и алгоритмов 🚀.

Определение

Сеть разработчиков Mozilla определяет метод сокращения в прототипе объекта Array следующим образом:

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

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

Хорошо, но когда и как я могу использовать эту функцию? Это только для суммирования всех чисел в массиве? Есть реальный пример? И что означают этот аккумулятор (acc), текущее значение (cur), текущий индекс (idx) и исходный массив (src)?

🧒🏻 Давайте погрузимся в детскую комнату за красивым объяснением.

Разноцветные блоки

Честно говоря, я совершенно неисправимый наркоман LEGO 🤪. Ах, эти цвета, формы и возможности построить из них все, что только можно вообразить ...

Теперь, когда у меня не так много времени на них, я предпочитаю, чтобы все наборы были собраны и выставлены на полке так, как они должны выглядеть в соответствии с моделью. Но время от времени (особенно когда дети получают в руки мою драгоценную коллекцию) все мои наборы смешиваются и вместе выбрасываются в большой контейнер. Ох, какой беспорядок ... А потом приходит время собрать все свои припасы, силы и мотивацию, чтобы вернуть их на свои полки.

Но подождите, а как насчет редукторов? Итак, прежде чем я смогу восстановить свою отображаемую коллекцию, мне нужно построить их, и для этого мне нужно знать, какая часть принадлежит какому набору. Тогда я смогу составить наборы с их инструкциями (как будто я не знаю инструкции наизусть 😁).

И вот пришло время моему мозгу использовать идеальный редуктор массива!

Давайте уменьшим кирпичи

Хорошо, поэтому для простоты примера предположим, что среди разных наборов нет общих блоков. Итак, я знаю, что если я увижу черный блок 2x2, я знаю, что он принадлежит моему B-Wing Fighter из Звездных войн, а все мои красные окна принадлежат старому семейному дому установить. Предположим, у меня есть только 3 набора LEGO: крыло B, комната запретного коридора Гарри Поттера и простой старый дом с белыми стенами и красной крышей.

Итак, вот мой контейнер со всеми перепутанными кирпичиками.

const bricks = [
    {set: 'b-wing', type: 'brick', size: '2x2', color: 'black'},
    {set: 'house', type: 'roof', size: '4x2', color: 'red'},
    {set: 'hp', type: 'spider', size: '1x1', color: 'black'},
    {set: 'b-wing', type: 'panel', size: '4x8', color: 'gray'},
    {set: 'b-wing', type: 'brick', size: '2x2', color: 'black'},
    {set: 'house', type: 'brick', size: '6x1', color: 'white'}
]

Я хочу разложить их по коробкам с наборами LEGO следующим образом:

{'b-wing': [], 'house': [], 'hp': []}

📥📥📥 Я не подготовил коробки с этикетками, поэтому буду делать это попутно, как только наткнусь на предмет, на котором еще нет коробки.

Итак, что я собираюсь сделать, это перебрать все кирпичи и поместить каждый из них в соответствующую коробку. Вот некоторые утверждения из процесса:

  1. Первоначально у меня нет коробок для каждого набора, но я знаю, что собираюсь поставить коробки на специальной полке.
  2. Я вынимаю новый кирпич из исходного контейнера, обрабатываю его в уме, решаю, где он принадлежит, и помещаю текущий кирпич в установленную коробку.
  3. Если для набора моей текущей части нет коробки, я создаю, маркирую новую коробку и кладу ее на полку.
  4. Каждый раз, когда я беру кирпич из исходного контейнера, я уменьшаю количество всех кирпичей, оставшихся для расстановки.
  5. Наконец, когда в исходном контейнере не осталось кирпичей для обработки, я смотрю на свою полку и вижу, что в моей смешанной кучке кубиков LEGO осталось превратился в структурированный набор помеченных коробок на моей полке.

Другими словами (или визуально) я преобразую стопку слева в организованную структуру справа:

👩🏻‍💻 Если бы кто-то закодировал весь этот процесс на JavaScript, используя метод Array.reduce(), это выглядело бы так:

const bricks = [....]; //the pile of bricks defined above
const shelf = bricks.reduce((shelfOfBoxes, brick, brickNumber, pile) => {
    console.log(`Checking the brick number ${brickNumber + 1}`);
    if(!shelfOfBoxes.hasOwnProperty(brick.set)) {
        shelfOfBoxes[brick.set] = [];  //add a new box if needed
    }
    shelfOfBoxes[brick.set].push(brick); //put the brick in its box
    console.log(`Bricks left: ${pile.length - (brickNumber + 1)}`)
}, {}); //the empty shelf
console.log(shelf);

А что у нас здесь?

  1. Изначально у меня есть смешанная кучка кирпичей, хранящаяся в массиве
  2. Изначально моя полка пуста. Второй аргумент в функции уменьшения - это начальное значение полки, которое является пустым объектом: {}
  3. Я просматриваю массив с помощью метода уменьшения
  4. На каждой итерации цикла я знаю следующее: текущая ситуация на полке (shelfOfBoxes), текущий кирпич, который я обрабатываю (brick), который является текущим индексом кирпича / сколько я уже обработал (brickNumber) и начальная связка кирпичей (pile)
  5. Во время каждого цикла я проверяю, есть ли на полке поле с заданным именем для моего текущего кирпича: if(!shelfOfBoxes.hasOwnProperty(brick.set))
  6. Если ящика нет, я добавляю новое пустое поле с меткой текущего кирпича, установленного на полке: shelfOfBoxes[brick.set] = [];
  7. Затем кладу текущий кирпич в коробку для его набора: shelfOfBoxes[brick.set].push(brick);
  8. Отмечу для себя, сколько кирпичей осталось в куче: console.log(`Bricks left: ${pile.length — (brickNumber + 1)}`)
  9. В итоге у меня есть shelf ящиков, заполненных всеми кубиками, принадлежащими каждому сетевому ящику.

Поэтому я использовал функцию reducer, чтобы преобразовать массив объектов во что-то совершенно другое. В этом цель метода Array.reduce().

Выполнено

Круто, теперь вы должны иметь представление о том, что такое reduce метод, каковы его аргументы и каков реальный пример, когда наш мозг работает как редуктор 🧠.

Конечно, у метода Array.reduce() есть и другие возможности и варианты использования. Вы также должны знать, что начальное значение преобразования необязательно. Я уже знаю другой пример, связанный с кирпичом для этого случая. Следите за новой статьей с подробным объяснением в ближайшее время 📢.

И, конечно же: