Глубокое понимание всемогущего Reducer

внешний интерфейс JavaScript
Глубокое понимание всемогущего Reducer

Перевод: Лю Сяоси

Оригинальная ссылка:CSS-tricks.com/понимаю я…

Другие статьи можно нажать: GitHub.com/Иветт Л.А. Ю/Б…

Есть несколько друзей, которые интересуются JavaScriptreduceМетода недостаточно для понимания, давайте посмотрим на следующие два фрагмента кода:

const nums = [1, 2, 3];
let value = 0;

for (let i = 0; i < nums.length; i++) {
    value += nums[i];
}
const nums = [1, 2, 3];
const value = nums.reduce((ac, next) => ac + next, 0);

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

reducerчто

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

Также необходимо отметить:reducerНе изменяйте по существу ваши исходные значения; вместо этого они возвращают что-то другое.

Давайте рассмотрим первый пример, чтобы вы могли увидеть, что здесь происходит, взгляните на гифку ниже:

Просмотр гифки может помочь всем нам, но давайте вернемся к коду:

const nums = [1, 2, 3];
let value = 0;

for (let i = 0; i < nums.length; i++) {
    value += nums[i];
}

множествоnums([1,2,3]) , первое значение каждого числа в массиве будет добавлено кvalue(0). Мы перебираем массив и добавляем каждый его элемент вvalue.

Давайте попробуем другой подход для достижения этой функциональности:

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = function (acc, item) { 
    return acc + item;
}

const total = nums.reduce(reducer, initialValue);

Теперь у нас тот же массив, но на этот раз мы не меняем начальное значение (т.е. в предыдущем кодеvalue). Здесь у нас есть начальное значение, которое используется только в начале. Далее мы можем создать функцию, которая принимает аккумулятор (acc) и элемент (item). Аккумулятор — это накопленное значение, возвращенное в предыдущем вызове (илиinitialValue), является входным значением для следующего обратного вызова. В этом примере вы можете представить его как снежный ком, катящийся с горы, съедающий каждое значение на своем пути, по мере того, как он растет на размер каждого съеденного значения.

мы будем использовать.reduce()чтобы получить эту функцию и начать с начального значения. Вы можете использовать сокращение функции стрелки:

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = (acc, item) => { 
    return acc + item;
}

const total = nums.reduce(reducer, initialValue);

Чтобы еще больше сократить длину кода, мы знаем, что стрелочные функции в отсутствие{}, по умолчаниюreturn;

const nums = [1, 2, 3];
const initialValue = 0;

const reducer = (acc, item) => acc + item;

const total = nums.reduce(reducer, initialValue);

Теперь мы можем применить эту функцию там, где она вызывается, или напрямую установить начальное значение, например:

const nums = [1, 2, 3];

const total = nums.reduce((acc, item) => acc + item, 0);

Аккумулятор может быть пугающим термином, поэтому, когда мы применяем логику к обратным вызовам, вы можете думать об этом как о текущем состоянии массива.

стек вызовов

Если непонятно, что происходит, давайте протоколировать каждую итерацию.reduceИспользуемая функция обратного вызова будет выполняться для каждого элемента в массиве. Демонстрация ниже поможет проиллюстрировать это более четко. Я использовал другой массив ([1, 3, 6]), потому что может сбивать с толку то, что число совпадает с индексом.

const nums = [1, 3, 6];

const reducer4 = function (acc, item) { 
    console.log(`Acc: ${acc}, Item: ${item}, Return value: ${acc + item}`);
    return acc + item;
}
const total4 = nums.reduce(reducer4, 0);

Когда мы выполняем этот код, мы видим следующий вывод в консоли:

Acc: 0, Item: 1, Return value: 1
Acc: 1, Item: 3, Return value: 4
Acc: 4, Item: 6, Return value: 10

Вот более интуитивная разбивка:

  1. аккумулятор(acc) от начального значения (initialValue): начиная с 0
  2. затем первыйitemравно 1, поэтому возвращаемое значение равно 1 (0+1=1)
  3. 1 становится аккумулятором при следующем звонке
  4. Теперь наш аккумулятор равен 1 (acc),item(второй элемент массива) равен 3
  5. Возвращаемое значение становится равным 4 (1+3=4)
  6. 4 становится аккумулятором при следующем вызове, следующий элемент при вызовеitem6
  7. Результат равен 10 (4 + 6 = 10), что является нашим окончательным значением, поскольку 6 — последний элемент в массиве.

Простой пример

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

Сколько у нас крестиков?

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

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82];

const result = nums.reduce((tally, amt) => {
    tally[amt] ? tally[amt]++ : tally[amt] = 1;
    return tally;
}, {});

console.log(result);
//{ '1': 1, '3': 2, '4': 1, '5': 2, '6': 1, '82': 2 }

Изначально у нас есть массив и объекты, которые будут в него помещены. существуетreducer, мы сначала определяем, существует ли элемент в аккумуляторе, и если да, прибавляем 1. Если он не существует, добавьте эту запись и установите для нее значение 1. Наконец, верните количество вхождений каждого элемента. Затем мы запускаемreduceфункция, при прохожденииreducerи начальное значение.

Возьмите массив и преобразуйте его в объект, отображающий определенные условия.

Предположим, у нас есть массив, и мы хотим создать объект на основе набора условий.reduceЗдесь отлично работает! Теперь мы хотим создать объект из любого элемента числа в массиве и отобразить как нечетную, так и четную версии этого числа.

const nums = [3, 5, 6, 82, 1, 4, 3, 5, 82];

// we're going to make an object from an even and odd
// version of each instance of a number
const result = nums.reduce((acc, item) => {
  acc[item] = {
    odd: item % 2 ? item : item - 1,
    even: item % 2 ? item + 1 : item
  }
  return acc;
}, {});

console.log(result);

Вывод консоли:


{ '1': { odd: 1, even: 2 },
  '3': { odd: 3, even: 4 },
  '4': { odd: 3, even: 4 },
  '5': { odd: 5, even: 6 },
  '6': { odd: 5, even: 6 },
  '82': { odd: 81, even: 82 } 
}

Когда мы перебираем каждый элемент в массиве, мы создаем свойство для четных и нечетных чисел и на основе встроенного условия с оператором по модулю мы либо сохраняем число, либо увеличиваем его на 1. Оператор по модулю отлично подходит для этого, потому что он может быстро проверить, четное оно или нечетное: если оно делится на 2, оно четное, если нет, то оно нечетное.

Другие источники

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

  1. Документация MDNОчень полезно для этого. Серьезно, это один из их лучших постов, и они также более подробно описывают, что произойдет, если вы не укажете начальное значение, о чем мы не упоминали в этом посте.
  2. Coding Train
  3. A Drip of JavaScript

Спасибо за вашу готовность потратить свое драгоценное время на чтение этой статьи. Если эта статья дала вам небольшую помощь или вдохновение, пожалуйста, не скупитесь на лайки и звезды. Вы, безусловно, самая большая движущая сила для меня, чтобы двигаться вперед .GitHub.com/Иветт Л.А. Ю/Б…

Подпишитесь на официальный аккаунт и присоединитесь к группе технического обмена