O forEach é uma das funções mais confusas de se entender no JavaScript, especialmente para iniciantes. Mas você sabe usá-la? Aprenda aqui!
Arrays em JavaScript são estruturas que armazenam diversos dados em uma única variável. Além dessa praticidade de acumular tudo em um só lugar, e também do seu tamanho variável, eles trazem consigo diversos métodos para fazer seu usufruto. Dentre estes, temos o forEach, que, em português, significa “para cada”. Esta é uma função que acaba sendo pouca usada, mas que, por vezes, se torna a melhor opção em ocasiões mais avançadas. Por isso, ela é um método que deve ser entendido e conhecido para que o programador se torne mais completo e proficiente na linguagem.
O forEach acaba é às vezes função confusa de se entender quando se está no começo da sua caminhada com o JavaScript. Ele funciona de uma forma diferente das demais funções de arrays, já que ela não tem um comportamento padrão. O usuário é que programaticamente diz o que é que essa função vai fazer com um array – o que pode ser complicado! No entanto, nada temas: iremos descomplicar o funcionamento do forEach passo por passo, começando pelos conceitos mais fundamentais.
E, para tanto, é preciso explicar que essa função se encaixa em um conceito da programação chamado de Higher Order Function (HOF). Esse é um tipo de função que não existe apenas no JavaScript, mas também em quase todas as linguagens. O nome pode parecer assustador, mas o assunto é um pouco mais simples do que aparenta. Sem mais delongas, vamos lá!
O que é uma Higher Order Function?
Uma HOF, ou função de nível superior em tradução direta do inglês, é um conceito matemático e da ciência da computação que define uma função que faz pelo menos um dos seguintes:
- Recebe uma função como parâmetro;
- Retorna uma função ao final da execução.
E, principalmente no JavaScript, a maioria das vezes que utilizamos esse tipo de função, nós enviamos outras funções como parâmetros. É pouco usual os casos em que retornamos funções de outras funções; embora seja perfeitamente usável, acaba acontecendo poucas vezes (a menos que ou você seja muito bom ou esteja tratando com componentes de frameworks, que são no fundo do fundo funções, mas isso é um assunto mais complexo). É por isso que as funções de alto nível, como o próprio forEach, não têm um comportamento pré-definido: ela faz exatamente aquilo que você passa como parâmetro.
É, portanto, uma função com alto grau de customização e que por vezes é de difícil entendimento à primeira vista, especialmente quando construída fora de algumas das estruturas pré-definidas da linguagem. Apesar de ser conceitualmente estranha, com a prática você se acostuma, após alguns usos. Fora o forEach, em JavaScript, temos ainda alguns outros exemplos de Higher Order Functions, como .map(), .filter(), .reduce() e mais algumas outras.
Como isso se aplica ao forEach?
Agora, chegamos ao nosso desejado forEach. Conforme citamos anteriormente, o nome da função significa “para cada”, e ela se aplica nos arrays. Portanto, pela lógica, entende-se de que se trata: ela aplica uma regra, definida pelo programador, a cada elemento de um array. E é por isso que ela é interessante para ocasiões um pouco mais complexas no uso dessa estrutura de dados. Vejamos agora a sintaxe básica do forEach:
Explicando por partes:
- array: se refere ao array no qual queremos que essa regra seja chamada;
- forEach: é a chamada da função de nível superior;
- elemento: é um parâmetro obrigatório que se refere ao elemento que está sendo iterado agora. Lembra que a regra do forEach se aplica a cada um dos elementos do array? É com esse parâmetro que você irá utilizá-los;
- index: é um parâmetro opcional que se trata de um índice de elemento fornecido pela própria função. É muito útil em frameworks que pedem que elementos renderizados em uma página web tenham índices próprios (como acontece no React, por exemplo);
- array: é um parâmetro opcional que trata de repassar o array em que o método forEach irá iterar (sim, a ideia de ter o próprio array passado como parâmetro é estranha, mas mais à frente fará sentido! Confie em mim);
- argumentos: é a função que será executada para cada índice do array.
Lidando com o callback
Agora que tivemos esse contato inicial com o forEach, é preciso explicar o que é o callback. A chamada função de callback, que é a que vem dentro dos parênteses do forEach (e, portanto, é a função passada como argumento para a outra função), está, no caso do exemplo dado antes, criada em formato de arrow function. No entanto, você pode também criar uma função externa e chamá-la dentro do callback, contanto que ela se encaixe à norma obrigatória, que é de ter pelo menos um parâmetro para ser iterado.
Vamos ver exemplos claros dessa função em execução:
A função de callback deve imprimir no console cada elemento do array array. Vejamos em execução:
Como o comportamento ocorre conforme previsto, vejamos agora a outra forma de desenhar essa função: vamos criar a função do callback em separado e apenas invocá-la como parâmetro para o forEach:
Como você pode ver, na chamada da função, sequer precisamos informar quais são as variáveis. Isso ocorre porque a própria implementação do método forEach entende esse uso, e pede apenas que a função passada como variável esteja conforme o requerido, que é aceitar pelo menos um parâmetro para servir de iterador. Essa forma de uso segue os princípios do código limpo por ser mais semântica e facilmente entendível, dado que ela reduz a quantidade de código aninhado e mantém intacto o preceito de que cada função deve fazer apenas uma coisa. É, portanto, preferível que se construa e chame a função do callback assim; contudo, sinceramente, às vezes a preguiça fala mais alto e acabamos fazendo da primeira forma, mesmo.
Utilizando os parâmetros index e array
Explorando um pouco mais da sintaxe da função forEach, vamos explorar o uso dos parâmetros index e array. Primeiro, adicionemos apenas o index:
Como você pode ver, pela própria sintaxe da função, não precisamos modificar nada na chamada do callback no forEach; ele irá entender o que está em execução sem problemas. Se atente para o fato de que eu modifiquei o array de entrada, para que não fique confuso. Agora, vejamos a execução:
Como se percebe, a função dá um índice ao elemento sendo iterado com base na sua posição do array de entrada, o que, como citado anteriormente, é útil para o uso em frameworks que pedem indexação para componentes repetidos. Por exemplo, em React, imaginemos um feed de notícias: cada notícia é uma repetição de um mesmo componente, sendo que cada um vai ser preenchido com dados diferentes extraídos do back-end. Então a livraria pede que cada um deles tenha um índice único, para que não haja bugs na experiência do usuário. É agora que o index vem a calhar!
Agora, vejamos o array:
Acontece basicamente a mesma coisa que no index, por isso, não é preciso repetir a explicação. No entanto, note que interessante: o array que está iterando é passado por inteiro para a função do callback, para que ela possa conhecê-lo. Dessa forma, não é preciso utilizar de uma variável global caso, por algum motivo, fosse preciso fazer uso do array por inteiro dentro do callback: a própria implementação da função oferece suporte para essa necessidade.
Avisos quanto ao forEach
Além dos problemas de legibilidade do forEach, que resolvemos em parte programando a função separadamente e chamando-a no callback, ela também sofre de um mal: é uma função com um tempo de execução inferior. Pela própria definição da função em JavaScript, ela sofre de problemas de lentidão se usada em arrays muito grandes. Por isso, por vezes, pode ser melhor construir um laço for e iterar sobre o array “à moda antiga”. Afinal de contas, se observarmos bem, é isso que o forEach faz: resume um laço for a uma simples função de nível superior, desta forma reduzindo a necessidade de codificar mais, às custas de um tempo de execução maior.
Claro, caso o array em questão seja pequeno, isso não será algo que irá atrapalhar o funcionamento do seu programa. É algo que se deve pensar, contudo, quando o código deve iterar 1000, 10.000 vezes, ou até mais. É problema para projeto grande! Portanto, no uso geral do forEach, você deve se preocupar com se o seu código está entendível e se é possível fazer manutenções nele, para aprimorá-lo ou consertá-lo. Isso é mais importante do que toda a parte conceitual “chique” que ensinamos aqui! Mantenha o seu projeto funcionando.
Lembre-se sempre daquela máxima ensinada no grande clássico Programador Pragmático: “O código complexo é aquele que evoluiu a partir do código simples que funcionava.”
E, caso tenha gostado desse artigo, lembre-se de recomendá-lo aos seus amigos! Até mais.