JavaScript: Métodos de Array - Parte 1: map, forEach, find e filter
Silvério Vale • 31 de janeiro de 2024
Um dos primeiros passos de todo novo programador é aprender a lidar com loops. É empolgante construir um while
ou um for
pela primeira vez. E é importante que o aprendizado comece por aí. Contudo, as linguagens modernas apresentam funcionalidades mais elegantes para lidar com listas em um nível de abstração mais alto.
Se você é um desenvolvedor JavaScript e se pega utilizando while
e for
com frequência, recomendo que leia este post e aprenda a deixar seu código mais legível e elegante.
Este é o primeiro texto da série JavaScript: Métodos de Array. Nele, vou apresentar quatro métodos que podem substituir os loops básicos e que poderão ser utilizados regularmente: o forEach
, o map
, o filter
e o find
.
As desvantagens do for
e o while
Por mais que funcionem, esses loops mais básicos deixam o controle da iteração por conta do desenvolvedor. Em alguns casos específicos isso pode ser interessante, porém, na maior parte das vezes, é apenas código extra para lidar com a indexação dos elementos.
Também, você tem que codificar a funcionalidade específica que deseja alcançar com aquele loop (busca, mapeamento, etc.) enquanto as funções mais modernas fazem isso para você.
No caso do while
é ainda pior: um pequeno erro de codificação pode fazer com que seu sistema fique em loop "eterno" e acabe crashando. Inclusive, por esse motivo, nas comparações abaixo vou utilizar apenas o for
.
Os métodos de instância Array
A classe Array
do JavaScript possui vários métodos estáticos e de instância, que são uma mão na roda. Mesmo que você não tenha se deparado diretamente com a classe Array
, você já deve ter visto muitas instâncias dela por aí, como: ["Luiza", "Gabriel", "Ana"]
ou [123, 456, 789]
.
Quando temos um array assim, podemos fazer uso de seus vários métodos de instância para iterar sobre ele e alcançar o resultado desejado. Por exemplo, o código [123, 456, 789].filter(item => item < 500)
irá retornar um novo array contendo todos os números menores do que 500 presentes no array original.
Da mesma forma, os métodos forEach
, map
e find
podem nos ajudar a iterar, mapear e encontrar um item, respectivamente. Logo abaixo, vou explicar cada um deles e colocar exemplos para que você já possa começar a usá-los assim que terminar essa leitura.
Preparando o ambiente
Nos exemplos abaixo, utilizarei um mesmo array inicial. Para não ter que declará-lo muitas vezes, vou fazer isso agora:
const names = ["Alice", "Bob", "Charlie", "Ted", "Eve"];
Pronto. Agora vamos explorar alguns métodos de instância.
forEach
O forEach
serve para iterar sobre um array e executar uma ação para cada elemento.
Por exemplo, suponha que você deseje logar no console cada nome contido em um array:
names.forEach((name) => console.log(name));
Para fazer isso com um for
, ficaria assim:
for (let i = 0; i < names.length; i++) {
console.log(names[i]);
}
Repare que, usando o for
, você foi responsável por lidar com a indexação dos elementos, enquanto o forEach
fez isso por você.
map
O map
, além de iterar sobre o array de forma semelhante ao forEach
, permite retornar os itens em um novo formato.
Imagine que você tenha um array de nomes e queira contar qual é o número de caracteres de cada um deles. Com o map
é fácil:
const namesLengths = names.map(name => name.length);
Já com o for:
const namesLengths = [];
for(let i = 0; i < names.length; i++) {
namesLengths.push(names[i].length);
}
Nestes casos, o for
te obriga a criar um array vazio e preenchê-lo durante as iterações. O map
toma conta disso para você.
filter
O filter
serve para selecionar apenas os itens que atendam a determinada condição. Ao retornar true
, ele entende que a condição foi atendida, e o item será retornado. Ao retornar false
, o item não será incluído no retorno.
Por exemplo, se você quiser filtrar apenas os nomes que possuam mais do que três caracteres, você faria assim:
const onlyBigNames = names.filter(name => name.length > 3);
Para fazer isso com o for
, novamente seria necessário lidar com a indexação e ir preenchendo um array aos poucos.
const onlyBigNames = [];
for(let i = 0; i < names.length; i++) {
if(names[i].length > 3) {
onlyBigNames.push(names[i]);
}
}
Você, caro leitor, há de concordar que usar o filter
é muito mais legível e elegante.
find
Por sua vez, o find
serve para encontrar no array um elemento que atenda a determinada condição. Diferente do filter
, que retorna todos os elementos que atendam à condição, o find
retorna apenas o primeiro encontrado.
Se quiséssemos encontrar um nome que termina com a letra "a", faríamos assim:
const nameWithTrailingA = names.find(name => name.endsWith("a"));
Já com o for
, ficaria assim:
let nameWithTrailingA = "";
for(let i = 0; i < names.length; i++) {
if(names[i].endsWith("a")) {
nameWithTrailingA = names[i];
break;
}
}
Com o for
, além de termos tido que lidar com a indexação, também tivemos que criar uma variável mutável e forçar uma parada do loop.
E se eu precisar do index?
É comum desenvolvedores retornarem ao for
quando precisam de utilizar o índice da iteração. Não há necessidade. Todos os métodos apresentados acima possuem o índice de iteração como um segundo parâmetro no callback interno.
Por exemplo, se quisermos mapear os nomes para objetos que utilizem o índice como identificador, poderíamos fazer assim:
const users = names.map((name, index) => ({id: index, name}));
Utilizando os métodos com propósito
Já encontrei desenvolvedores que começaram a usar os métodos de instância mencionados, mas ignorando o propósito de cada um.
Por exemplo, considerando o caso anterior, onde queríamos mapear os nomes para objetos com identificadores, o dev poderia se sentir tentado a fazer algo do tipo:
const users = [];
names.forEach((name, index) => {
users.push({id: index, name})
})
Se fizesse isso, o dev estaria ignorando o propósito de cada método de instância. Estaria usando um forEach
para mapear - algo que é próprio do map
.
Para conhecer melhor as diversas opções das quais podemos lançar mão, continue acompanhando essa série sobre JavaScript - Métodos de Array.