JavaScript: Métodos de Array - Parte 1: map, forEach, find e filter

Silvério Vale • 31 de janeiro de 2024

Thumbnail com a logo do JavaScript e o título abreviado do post. No background, um código ofuscado.

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.

Referências

© 2023 Cartas de um Dev. Todos os Direitos Reservados.