Содержание
Данный метод наверное наиболее сложный из методов массивов. Давайте рассмотрим как с ним работать и разберем несколько примеров где он может применяться.
Метод reduce() выполняет заданную функцию к каждому элементу массива и возвращает «аккумулированный» результат.
array.reduce(function(total, currentValue, currentIndex, arr))
total — начальное значение или ранее возвращенное значение (из предыдущей итерации).currentValue — текущее значение массиваcurrentIndex — индекс текущего элементаarr — проходимый массив
Примеры использования
Наиболее наглядный пример — это подсчет суммы значений элементов массива. Например, у нас есть такой массив:
const salary = [1000, 1200, 900, 1800];
const sum = salary.reduce((total, currentItem) => {
total += currentItem;
return total;
}, 0) // 0 - это начальное значение, тут мы могли бы указать другое число
console.log('sum', sum); // 4900
Рассмотрим другой пример. У нас есть массив пользователей. Каждый пользователь это обьект. У каждого пользователя есть имя, возраст и размер компенсации. Нам нужно высчитать среднюю заработную плату:
const users = [
{ name: 'John', age: 32, salary: 1500 },
{ name: 'Mike', age: 25, salary: 1200 },
{ name: 'Pieter', age: 27, salary: 1400 },
{ name: 'Jim', age: 22, salary: 1800 }
];
const averageSalary = users.reduce((total, user) => {
total += user.salary/users.length;
return total;
}, 0);
console.log('Average Salary', averageSalary); // 1475
Если в примере выше у вас users это не массив, а объект и задача та же — посчитать среднюю з/п, тогда мы можем сделать так:
const users = {
0: { name: 'John', age: 32, salary: 1500 },
1: { name: 'Mike', age: 25, salary: 1200 },
2: { name: 'Pieter', age: 27, salary: 1400 },
3: { name: 'Jim', age: 22, salary: 1800 }
}
// Определяем количество элементов в объекте
const userObjLength = Object.keys(users).length;
const averageSalary = Object.keys(users).reduce((total, key) => {
// В [key] у нас попадает ключ с обьекта users (от 0 до 3)
total += users[key].salary/userObjLength;
return total;
}, 0);
console.log('Average Salary', averageSalary); // 1475
Преобразование массива в объект с помощью reduce
В двух последних примерах у нас есть массив users и есть объект users. А что если нам нужно преобразовать массив в объект? Для этого мы также можем воспользоваться методом reduce()
const users = [
{ name: 'John', age: 32, salary: 1500 },
{ name: 'Mike', age: 25, salary: 1200 },
{ name: 'Pieter', age: 27, salary: 1400 },
{ name: 'Jim', age: 22, salary: 1800 }
]
const usersObj = users.reduce((acc, user, index) => {
acc[index] = user
return acc;
// Начальное значение {}
}, {});
console.log('New Object', usersObj);
Так как на выходе нам нужен объект, мы вторым параметром в метод reduce передаем пустой объект и дальше на каждой итерации добавляем ему новую пару «ключ — значение». В качестве ключа у нас выступает индекс текущего элемента в массиве.
Пишем свой метод reduce на JavaScript
Мы разберем два примера: простой и более сложный, в котором будут обрабатываться ошибки и проверяться условия.
Первый пример:
Array.prototype.customReduce = function(callback, result) {
let i = 0;
// Проверяем если кол-во аргументов меньше 2, значит не передано дефолтное значение
if (arguments.length < 2) {
i = 1;
// В данном случае this указывает на итерируемый массив
result = this[0]
}
for (; i < this.length; i++) {
result = callback(result, this[i], i, this);
}
return result;
}
Мы сразу добавили данный метод к прототипу массива, чтобы его можно было легко вызвать. Теперь проверим выдаст ли он нам такой же результат, как был в самом первом примере этого поста:
const salary = [1000, 1200, 900, 1800];
const sum = salary.customReduce((total, currentItem) => {
total += currentItem;
return total;
}, 0);
console.log('sum', sum); // 4900
Теперь давайте рассмотрим более сложный вариант с дополнительными проверками:
Array.prototype.customReduce = function(callBack, initialValue) {
// Проверяем не пустой ли массив и задано ли дефолтное значение
if (!this.length && initialValue === undefined)
throw new TypeError('Массив пустой. Невозможно к нему применить данный метод');
// Если дефолтное значение задано, то присваиваем его к accumulator, который в итоге будем возвращать
let accumulator = initialValue;
let index = 0;
if (initialValue === undefined) {
// Если нет дефолтного значения, тогда accumulator будет присваиваться значение первого элемента массива
accumulator = this[0];
index = 1;
}
// В цикле проходимся по нашему массиву и передаем наш callback, который нужно выполнить для каждого элемента массива
for (; index < this.length; index++) {
// Как мы помним метод reduce принимает 4 параметра (см начало поста)
// Поэтому мы в наш callback передаем такие же 4 параметра
accumulator = callBack(accumulator, this[index], index, this);
}
return accumulator;
}
Если остались вопросы — пишите в комментарии.
Добавить комментарий