Javascript: Entendendo o reduce() de uma vez por todas

Raul Esteves
3 min readJan 18, 2019

O reduce, ah o reduce. Tão falado porém tão pouco compreendido.
Isso acaba hoje, aqui e agora, pois iremos entender o reduce de uma vez por todas /o/.

Pois bem, o reduce() começou a se popularizar com o ES6, junto das funções map() e filter() que relembraram a pegada funcional do javascript.

Beleza, e pra que ele serve?
Como o nome sugere, o reduce busca reduzir um array. Ele iterará por cada elemento dessa lista com o objetivo de ao final gerar um único valor (de qualquer tipo), como por exemplo a soma de todos os elementos desse array. Lembrando que não ficamos presos apenas a números.

Entendi, mas como usa-lo?
Todo array tem ele como método e a assinatura é muito mais simples do que parece, se liga só:

const callback = (
acumulador,
elementoAtual,
indexAtual,
arrayOriginal
) => {};
const valorInicial = XX;const lista = []const reducedValue = lista.reduce(
callback(
acumulador,
elementoAtual,
indexAtual,
arrayOriginal
),
valorInicial
)

Temos: temos a função callback, o valor inicial do reduce e a lista ao qual
iremos iterar chamando o callback.
Na função callback podemos passar quatro argumentos:
* A variável que vai servir como acumuladora (que é o valor retornado na ultima iteração e inicia com o valor inicial) (obrigatório).
* O valor do atual elemento sendo iterado (obrigatório).
* O índice do elemento atual (não é obrigatório).
* O array original (não é obrigatório).

Caso o valor inicial não seja passado, o acumulador iniciará com o valor do primeiro elemento da lista.

Inicialmente vou usar uns exemplos chatos com números, mas prometo que no final vão ter ideias diferentes! O ultimo é o caso que me faz mais usar o reduce. :)
Tá, chega de preguiça e vamos ver acontecendo! Abre o console aí e bora (botão direito do mouse > inspecionar > guia console):

Caso você seja um tremendo preguiçoso e não tenha rodado o código, retornará o seguinte:

Ora ora, parece que é apenas um loop, sendo que o retorno é sempre acrescido ao acumulador.
Bacana e bem simples né? Que tal agora uns exemplos um pouco mais interessantes?

Lembra do argumento valorInicial? Vamos passar nele um outro array também com a função reduce para somar as duas listas, pegou a ideia? Se liga só:

Roda no console aí pra ver. O resultado vai ser 55.
O acumulador do array a, vai começar com o valor do reduce do array b.

Agora vamos tentar algo um pouquinho mais ousado, brincando com o seguinte array de objetos:

Se quisermos filtrar apenas os cães, calcular a idade real deles (dizem que cada ano canino é equivalente a 7 anos nossos) e fazer uma soma disso, como podemos fazer?
Utilizando o filter (pra filtrar, duh), o map (para realizar o calculo em cada elemento) e o reduce (para somarmos tudo). Ex:

Mas que tal tentarmos tudo isso dentro de um único reduce?

Poxa legal, mas que tal utilizarmos o reduce com uma string html?

Agora meu uso preferido! Indexar listas de objetos pelo id!
Vamos pensar na seguinte lista:

// se a lista for grande, e eu ficar precisando buscar carros a todo momento, não vai ser legal ficar iterando pela lista (complexidade O(n), então eu gosto de indexar pra ficar com a complexidade O(1).
Performaticamente pode salvar a sua vida, se liga:
const lista = [
{id: 1, nome: "gol"},
{id: 2, nome: "ferrari"},
{id: 3, nome: "camaro :)"}
];
const callback = (acumulador, valor) => {
acumulador[valor.id] = valor.nome
return acumulador
};
const valorInicial = {};const carrosIndexadosPorId = lista.reduce(callback, valorInicial);console.log(carrosIndexadosPorId[3]) //camaro :)

Legal né?

Enfim, foram exemplos bem simples mas acho que deu pra captar a ideia.
Vamos buscar extrair ao máximo o que esses carinhas podem nos oferecer.

Por hoje é só, espero ter ajudado e até a próxima!

Bibliografia:
https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://www.w3schools.com/jsref/jsref_reduce.asp
Ex dos animais inspirado hein:
https://medium.com/@programadriano/javascript-conhecendo-map-filter-e-reduce-ce072d8f0ec5

--

--