JavaScript Filter é um método importantíssimo para se saber utilizar. Ele filtra arrays conforme você quiser. Mas você sabe usá-lo?
Por vezes, quando estamos programando em JavaScript, acabamos precisando remover uma determinada quantidade de elementos de um array. Isso pode se dar simplesmente para reduzir o número de índices ou então para remover alguns elementos que tenham alguma propriedade indesejada. É algo bastante comum em arrays que contenham objetos dentro, mas, por vezes, precisamos filtrar também, por exemplo, alguns números ou strings.
De um jeito ou de outro, este é um método importantíssimo de se conhecer. Quando você menos esperar, ele será usado, especialmente em testes técnicos e desafios lógicos! Isso porque este é um método que não modifica o array original, mantendo-o intacto e retornando o array filtrado para uma nova variável. É, portanto, um método muito útil para a manutenção daquela que é a estrutura mais importante em todo o JavaScript.
É, também, mais um método de nossa série sobre arrays, e mais um que envolve o uso de Higher Order Functions (HOFs). Vamos explicar isso melhor mais para frente. Junto com ele, temos os métodos JavaScript forEach e o método Map. Quanto ao Filter, tal como os dois métodos citados, podemos também dizer que ele resume um laço for. Isso porque ele funciona como se criasse um novo array, percorresse o original decidindo o que entra no novo ou não, e então retornasse o novo. No entanto, é tudo feito de uma forma mais prática e até mais sintática, através da execução de uma função de callback.
No entanto, o que é função de callback? Vamos começar a explicar o Filter pelo conceito do que é uma higher order function.
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 Filter, em JavaScript, temos ainda alguns outros exemplos de Higher Order Functions, como o .map(), .forEach, .reduce() e mais algumas outras.
Como isso ocorre com o JavaScript Filter?
Finalmente, agora estamos prontos para entender como ocorre a chamada de uma função dentro da função Filter. Como já explicamos antes, a estrutura irá percorrer um array aplicando a função determinada no callback para cada elemento. De seguido, após a execução, irá retornar um novo array, deixando o original intacto. Por isso, é indispensável que haja um return na função a ser chamada no callback: assim o array novo poderá ser criado. Se esse return estiver em falta, a sua IDE irá certamente lançar algum aviso de erro.
Agora, vamos ver a estrutura do funcionamento do método:
Explicando cara elemento:
- resultado: se refere ao array que será entregue ao final da execução do método
- array: é o array inicial, o qual se deseja que seja filtrado
- filter: a chamada do método de filtragem
- entrada: se refere ao elemento que está sendo iterado atualmente, isto é, aquele que o método lerá a cada execução. Este é um parâmetro obrigatório na função de callback.
- index: se refere ao índice desse elemento citado. Este é um parâmetro opcional na função.
- array: se refere ao array inicial por inteiro, que talvez o usuário possa querer usar durante a execução. É, também, um parâmetro opcional na execução.
- argumento: se trata da função que será executada, finalmente, para cada índice do array
Alguns exemplos da execução do método JavaScript Filter
Agora, vamos ver de verdade como que isso se aplica na prática. O conceito de utilizar funções de callback é muito abstrato de início, até que se tenha costume com a aplicação prática. Como é possível que uma função receba outra função como parâmetro? Pois bem, é estranho mas acontece. No entanto, quando trabalhamos com frameworks, acontece que lidamos com isso o tempo todo, já que, por exemplo, um componente React por debaixo dos panos é uma função. Só é estranho quando fazemos isso de forma “crua”, sem toda a proteção do que é um componente. Sem mais delongas, vamos lá!
Esse é um método bastante simples. Ele filtra o array com base nos elementos pares. Portanto, o array de saída só conterá os números que forem pares. Como você pode ver, a comparação feita no return testa se a entrada é par; essa ordem é importante e pode ser confusa: aquelas que passam na regra definida na função estarão presentes no array de saída. O resultado, então, será assim:
No entanto, existem formas mais bonitas de se fazer isso. É perfeitamente possível, e até mesmo recomendável, declarar a função que será chamada fora da chamada do filter. Segue melhor as práticas do clean code, é mais legível, mais escalável e também melhor de se encontrar e modificar depois. Vejamos:
A função é executada exatamente da mesma forma, mesmo que não adicionemos as variáveis na chamada da função. É até mais fácil e mais simples de se entender. Agora, vejamos como funciona adicionando as demais variáveis na função:
E vamos ver a execução apenas por desencargo de consciência:
Outros exemplos de uso do método Filter
Existem ainda muitas outras formas de se utilizar o método Filter. Por exemplo, pode ser que tenhamos arrays de objetos, e precisamos comparar algumas propriedades desses objetos para decidir o que fica ou não. No entanto, a lógica sempre se mantém a mesma: deve-se fazer uma comparação entre elementos e retornar o caso que deve ser aceito. Esse caso, então, é o que estará presente no array de resultado. Vamos, agora, ver um exemplo com arrays de objetos:
Filtrando arrays de objetos
Vamos definir aqui o nosso exemplo:
Como você pode ver, temos um array com um catálogo de bebidas e seus respectivos preços fictícios e arbitrários. E queremos filtrar, então, os elementos que têm o preço menor que 70; o resultado, é claro, será apenas o objeto Suco de limão. Portanto, na função, testamos se a propriedade preco do elemento é menor que 70. Vejamos o resultado:
Essa testagem pode ser ampliada para um caso mais difícil:
Removendo objetos com propriedades inválidas
Às vezes, por algum motivo, acabamos recebendo arrays de propriedades inválidas. Coisas como valores nulos, inválidos ou simplesmente coisas que não desejamos que estejam em nosso programa para ser processados. Vejamos como fazer a testagem completa de como filtrar arrays com ids inválidos:
No exemplo, aumentamos um pouco o array e adicionamos id’s. Veja bem: apenas um tem um id válido, enquanto o resto tem null, NaN ou undefined. Por isso, são executados três casos de teste na função de callback, para que seja tudo filtrado e reste apenas o objeto válido, que é Néctar.
E este é o resultado. Como você pode ver, a gama de usos é bastante extensa, mas todos seguem o mesmo princípio: deve haver um teste e retornar o valor que seja true. É até possível criar o método sem que haja um return, mas o funcionamento não será conforme o ideal e o método ficará sem sentido, na verdade. Por isso, é importante seguir as regras de funcionamento!
Aviso quanto ao método Filter
Além dos problemas de legibilidade do Filter, 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 uma função de filtragem personalizada, utilizando algoritmos de estruturas de dados avançadas, utilizando de design patterns ou então de recursividade.
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 Filter, 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.
E, caso tenha gostado desse artigo, lembre-se de recomendá-lo aos seus amigos! Até mais.