
Todo programador já sabe que estruturas de repetição são essenciais em linguagens de programação. O while , o for e o do while se tornam nossos companheiros inseparáveis logo no início da carreira. Além disso, eles são muito úteis quando queremos operar sobre vetores, certo? Mas, às vezes, podemos fazer melhor 😁. O objetivo deste post é apresentar métodos simples do objeto Array em JavaScript que aplicam princípios de programação funcional e podem melhorar a legibilidade do seu código. A programação funcional é muito defendida no ambiente do JS por autores consagrados, como Eric Elliot e Kyle Simpson, e ganhou força com o EcmaScript 6, que já é vastamente suportado.
map, filter e reduce: os personagens principais
Todo array em JavaScript apresenta métodos de iteração utilitários para propósitos específicos. Aqui estão três mais relevantes:
Array.prototype.map() recebe uma função de transformação a ser aplicada a cada elemento do array e retorna uma coleção com os elementos transformados por essa função.
const vetor = [1, 2, 3, 4];
const vetorDobrado = vetor.map(function(x) {
return 2 * x;
});
console.log(vetorDobrado) // 2, 4, 6, 8
O código fica mais legível com o uso de arrow functions👍:
const vetor = [1, 2, 3, 4]; const vetorDobrado = vetor.map(x => 2 * x); console.log(vetorDobrado) // 2, 4, 6, 8
Array.prototype.filter() recebe uma função para filtragem do array. Ela deve retornar true se o elemento passa no filtro e false caso contrário.
const vetor = [1, 2, 3, 4]; const elementosPares = vetor.filter(x => x % 2 == 0); console.log(elementosPares) // 2, 4
Array.prototype.reduce() é um pouco mais complexo, utilizado para reduzir o conteúdo de um array a um único valor. Ele recebe dois parâmetros: a função de redução, que será aplicada a cada elemento, e o valor inicial de redução.
Por sua vez, a função de redução deve receber dois argumentos principais: o valor reduzido até agora, e o valor do elemento sendo iterado.
Se quiser somar todos os elementos, por exemplo:
const vetor = [1, 2, 3, 4]; const soma = vetor.reduce((acumulado, atual) => acumulado + atual, 0); console.log(soma) // 10
No trecho acima, definimos que o valor inicial de redução é zero, e a cada iteração a função de redução deve retornar a soma do valor de redução acumulado com o valor do elemento daquela iteração. Na primeira iteração, realiza-se 0 + 1 = 1. Depois, 1 + 2 = 3. Em seguida, 3 + 3 = 6 e, por fim, 6 + 4 = 10
Juntando forças
Como map e filter retornam arrays, é possível encadear esses métodos. Isso possibilita que operações mais elaboradas sejam feitas de forma bem limpa. Essa prática é chamada piping. Em inglês, pipe significa “cano”, o que se assemelha ao fluxo dos dados quando são encadeados.
Agora vamos à um exemplo mais contextualizado. Imagine que você precise saber a quantidade de filhos das pessoas adultas em um array de pessoas:
const pessoas = [
{
nome: 'Joaquim',
idade: 30,
quantidadeFilhos: 2,
},
{
nome: 'Ana',
idade: 45,
quantidadeFilhos: 3,
},
{
nome: 'Creuza',
idade: 88,
quantidadeFilhos: 8,
},
];Supondo que um adulto é alguém com menos de 65 anos, pode-se realizar essa tarefa da seguinte maneira:
const IdadeIdosos = 65;
const quantidadeFilhosDosJovens = pessoas
.filter(pessoa => pessoa.idade < IdadeIdosos)
.map(pessoa => pessoa.quantidadeFilhos)
.reduce((quantidadeTotal, quantidade) => quantidadeTotal + quantidade, 0);
console.log(quantidadeFilhosDosJovens); // 5Quando a estrutura do map, filter e reduce já estiverem familiares, você perceberá que o código se torna muito mais legível do que a versão imperativa:
const IdadeIdosos = 65;
let quantidadeFilhosDosJovens = 0;
for (let i = 0; i < pessoas.length; i++) {
if (pessoas[i].idade < IdadeIdosos) {
quantidadeFilhosDosJovens += pessoas[i].quantidadeFilhos;
}
}
console.log(quantidadeFilhosDosJovens); // 5Chique, né? E se você quiser o máximo da legibilidade, basta atribuir as funções utilizadas a variáveis e repassá-las aos métodos que foram aprendidos:
const IdadeIdosos = 65;
const ehJovem = pessoa => pessoa.idade < IdadeIdosos;
const obterQuantidadeFilhos = pessoa => pessoa.quantidadeFilhos;
const somar = (quantidadeTotal, quantidade) => quantidadeTotal + quantidade;
const quantidadeFilhosDosJovens = pessoas
.filter(ehJovem)
.map(obterQuantidadeFilhos)
.reduce(somar, 0);
console.log(quantidadeFilhosDosJovens); // 5Existem outros métodos do objeto Array que também contornam a necessidade de utiliza-se um laço for . Confira na página da MDN os métodos .find() , .some() , .every() e .includes() para aprender mais.
Conclusão
O ES6 trouxe novas maneiras de operar sobre arrays. Esses novos caminhos são mais legíveis, por serem mais declarativos, melhoram a reutilização de código e utilizam toda a força da característica multi-paradigma do JavaScript. Com todas essas novas ferramentas em mãos, são pouquíssimos os casos em que a utilização de um for nativo é imprescindível.
