Domine JavaScript: 11 Funções Essenciais para Devs Ágeis

Desvende o Poder do JavaScript: Funções Essenciais para Desenvolvedores Ágeis

Torne-se um mestre do JavaScript, elevando sua velocidade, produtividade e satisfação ao dominar as funções mais cruciais e recorrentes desta linguagem versátil.

Do back-end ao front-end, e até mesmo em aplicações espaciais, o JavaScript se faz presente em cada canto do universo digital. Sua notável flexibilidade, que permite abordagens de programação funcional robustas e a tradicional orientação a objetos, além de sua familiaridade com outras linguagens derivadas do “tipo C”, facilita a adoção por desenvolvedores de diferentes origens.

Se o seu objetivo é aprimorar suas habilidades em JS, dedique-se a aprender, praticar e dominar as seguintes funções fundamentais. Embora nem todas sejam estritamente “obrigatórias” para resolver problemas, elas podem simplificar tarefas complexas e reduzir a quantidade de código necessário.

map()

Seria negligente escrever sobre funções JavaScript essenciais sem mencionar map()! 😆😆 Juntamente com filter() e reduce(), map() forma um trio essencial. Essas funções serão suas companheiras constantes ao longo da carreira, por isso, vale a pena compreendê-las.

map() muitas vezes apresenta dificuldades para quem está aprendendo JavaScript, não por sua complexidade inerente, mas por ser uma ideia da Programação Funcional. Em um cenário dominado pela programação orientada a objetos, essa abordagem pode parecer estranha.

O JavaScript possui uma essência funcional, embora as versões modernas tentem disfarçar esse fato. Mas essa é uma discussão para outro momento. 🤣 Vamos focar em map().

map() é uma função simples que opera sobre um array e transforma cada item em algo diferente, resultando em um novo array. A lógica de transformação é definida por outra função, geralmente anônima.

Essa é a base da função! A sintaxe pode exigir algum tempo de adaptação, mas o conceito é simples. Por que usar map()? Depende do objetivo. Imagine que você registrou as temperaturas diárias da última semana em um array, mas descobriu que os instrumentos registraram 1,5 graus abaixo do valor correto.

Você pode corrigir esses dados com map():

    const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];
    const correctedWeeklyReadings = weeklyReadings.map(reading => reading + 1.5);
    console.log(correctedWeeklyReadings); // Resultado: [ 21.5, 23.5, 22, 20.5, 22.5, 23, 24.5 ]
  

Outro exemplo prático é o React, onde a criação de listas de elementos DOM a partir de arrays é comum. Veja um exemplo:

      export default ({ products }) => {
        return products.map(product => {
          return (
            <div className="product" key={product.id}>
              <div className="p-name">{product.name}</div>
              <div className="p-desc">{product.description}</div>
            </div>
          );
        });
      };
    

Este componente React recebe uma lista de produtos e a converte em uma lista de divs HTML, mantendo o array de produtos original intacto.

Você pode considerar map() como um loop for aprimorado, e você estaria certo. Mas essa é uma visão orientada a objetos, enquanto map() e sua lógica vêm da Programação Funcional, onde a uniformidade, a compacidade e a elegância são altamente valorizadas. 🙂

filter()

filter() é uma função extremamente útil para diversas situações. Como o nome sugere, ela filtra um array com base em uma lógica fornecida, retornando um novo array com os itens que atendem a essa lógica.

Reutilizando o exemplo do clima, vamos descobrir quantos dias da última semana tiveram temperaturas máximas abaixo de 20 graus. Utilize filter() para isso:

      const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];
      const colderDays = weeklyReadings.filter(dayTemperature => {
        return dayTemperature < 20;
      });
      console.log("Total de dias mais frios na semana: " + colderDays.length); // Resultado: 1
    

A função anônima passada para filter() deve retornar um booleano, indicando se o item deve ser incluído no array filtrado. Essa função pode conter qualquer lógica complexa, desde que retorne um booleano.

Atenção: muitos programadores criam bugs sutis ao usar filter(). Veja um exemplo:

    const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];
    const colderDays = weeklyReadings.filter(dayTemperature => {
      return dayTemperature < 20;
    });
    if(colderDays) {
      console.log("Sim, houve dias mais frios na semana passada");
    } else {
      console.log("Não, não houve dias mais frios");
    }
  

O erro está na condição if, que verifica colderDays, que é um array. No JavaScript, um array vazio [] é avaliado como true em uma condição if. A correção é verificar colderDays.length, que retornará um número inteiro.

Lembre-se: filter() sempre retornará um array, vazio ou não, e isso deve ser levado em consideração em suas comparações lógicas.

reduce()

reduce() é uma das funções mais complexas e estranhas do JavaScript. Embora seja poderosa e resulte em código elegante, muitos desenvolvedores preferem evitá-la.

A dificuldade reside na sua compreensão, tanto no conceito quanto na execução. A descrição da função pode exigir várias leituras, e a visualização do seu funcionamento pode ser desafiadora. 🤭

Mas não se assuste. reduce() não é tão complexa quanto, digamos, Árvores B+. Acontece que esse tipo de lógica raramente é encontrado no dia a dia do programador.

Como o nome sugere, reduce() é usada para reduzir um array a um único valor (número, string, função, objeto etc.). Diferentemente de map() e filter(), reduce() não retorna um array.

Para reduzir um array, é necessário fornecer a lógica por meio de uma função redutora, que é o primeiro argumento de reduce(). O segundo argumento é um valor inicial. (Explicarei o valor inicial mais adiante).

Uma chamada a reduce() tem esta forma: array.reduce(reducerFunction, StartingValue). A função redutora define como o array é transformado em um valor. Ela recebe dois argumentos: um acumulador e o valor atual.

O “valor inicial” é o ponto de partida para o cálculo. Se você for multiplicar os valores, o valor inicial pode ser 1; para adição, pode ser 0.

A função redutora tem o formato: reducerFunction(accumulator, currentValue). O acumulador armazena o resultado do cálculo. A função redutora itera sobre os itens do array, realizando o cálculo e atualizando o acumulador.

O “valor atual” é o valor do item do array que está sendo processado na iteração atual.

Vamos ver um exemplo: calcular o fatorial de um número usando reduce():

      const numbers = [1, 2, 3, 4, 5];
      const factorial = numbers.reduce((acc, item) => acc * item, 1);
      console.log(factorial); // Resultado: 120
    

Nesse código, o valor inicial do acumulador é 1. A função redutora (acc, item) => acc * item multiplica cada item do array pelo acumulador. A iteração e o armazenamento da multiplicação no acumulador ocorrem “nos bastidores”.

Por que usar reduce()? Tudo que reduce() faz pode ser feito com loops, forEach(), etc. No entanto, reduce() pode simplificar o código e garantir a imutabilidade dos dados, além de sua flexibilidade.

Se você ainda não está convencido, tudo bem. Mas procure exemplos práticos antes de descartá-lo. Exemplos práticos podem te ajudar a entender o poder da função.

some()

Imagine que você tem um array de objetos, cada um representando uma pessoa. Você quer saber se há alguém com mais de 35 anos. Não precisa saber quantos são, apenas se existe pelo menos um.

É possível usar um loop com uma variável de flag para resolver isso:

      const persons = [
        {
          name: 'Person 1',
          age: 32
        },
        {
          name: 'Person 2',
          age: 40
        },
      ];
      let foundOver35 = false;
      for (let i = 0; i < persons.length; i ++) {
        if(persons[i].age > 35) {
          foundOver35 = true;
          break;
        }
      }
      if(foundOver35) {
        console.log("Sim, há algumas pessoas aqui!")
      }
    

Mas esse código é muito parecido com C ou Java, o que o torna verboso e pouco elegante. A função some() é uma alternativa concisa e elegante. Ela recebe uma função de “filtragem” personalizada e retorna um booleano.

      const persons = [
        {
          name: 'Person 1',
          age: 32
        },
        {
          name: 'Person 2',
          age: 40
        },
      ];
      if(persons.some(person => {
          return person.age > 35
      })) {
        console.log("Encontrei algumas pessoas!")
      }
    

O código é mais conciso, legível e fácil de entender.

every()

Assim como some(), every() retorna um booleano. Mas, neste caso, o resultado depende se todos os itens do array passam em um teste fornecido.

      const entries = [
        {
          id: 1
        },
        {
          id: 2
        },
        {
          id: 3  
        },
      ];
      if(entries.every(entry => {
        return Number.isInteger(entry.id) && entry.id > 0;
      })) {
        console.log("Todas as entradas têm um id válido")
      }
    

O código verifica se todos os objetos do array têm uma propriedade id válida, onde “válido” é definido como inteiro positivo.

includes()

Como verificar a existência de substrings e elementos de arrays? indexOf() é uma opção, mas includes() é mais prática. includes() retorna um booleano, indicando se o elemento ou substring está presente. A comparação é feita com diferenciação de maiúsculas e minúsculas.

      const numbers = [1, 2, 3, 4, 5];
      console.log(numbers.includes(4));
      const name = "Ankush";
      console.log(name.includes('ank')); // Resultado: false
      console.log(name.includes('Ank')); // Resultado: true
    

includes() não funciona com objetos:

      const user = {a: 10, b: 20};
      console.log(user.includes('a')); // Gera erro
    

E ao tentar usar includes() em arrays de objetos:

       const persons = [{name: 'Phil'}, {name: 'Jane'}];
       persons.includes({name: 'Phil'}); // Resultado: false
     

Isso ocorre devido ao modo como o JavaScript lida com objetos e referências na memória. A solução é criar uma referência para o objeto:

      const phil = {name: 'Phil'};
      const persons = [phil, {name: 'Jane'}];
      persons.includes(phil); // Resultado: true
    

slice()

Se você precisa extrair parte de uma string ou array, slice() é a função ideal. Ela cria uma nova string/array a partir de uma já existente.

      const headline = "And in tonight's special, the guest we've all been waiting for!";
      const startIndex = headline.indexOf('guest');
      const endIndex = headline.indexOf('waiting');
      const newHeadline = headline.slice(startIndex, endIndex);
      console.log(newHeadline); // Resultado: guest we've all been
    

O índice final não é incluído no resultado. slice() cria cópias superficiais, evitando problemas de desempenho.

splice()

splice() remove, altera ou adiciona elementos em um array, modificando o array original. Essa é a principal diferença entre splice() e slice(). É importante ter cuidado ao usar splice(), pois ele altera o array original.

      const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
      items.splice(2, 1);
      console.log(items); // Resultado: [ 'eggs', 'milk', 'bread', 'butter' ]
    

A chamada splice(2, 1) remove um elemento do índice 2. Os itens removidos são retornados em um novo array.

shift()

shift() remove o primeiro elemento de um array.

      const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
      items.shift()
      console.log(items); // Resultado: [ 'milk', 'cheese', 'bread', 'butter' ]
    

unshift()

unshift() adiciona um novo elemento ao início de um array.

      const items = ['eggs', 'milk'];
      items.unshift('bread')
      console.log(items); // Resultado: [ 'bread', 'eggs', 'milk' ]
    

Tenha cuidado ao usar shift() e unshift() em arrays grandes, pois eles podem ser ineficientes.

fill()

fill() preenche parte ou todo o array com um valor.

      const heights = [1, 2, 4, 5, 6, 7, 1, 1];
      heights.fill(0);
      console.log(heights); // Resultado: [0, 0, 0, 0, 0, 0, 0, 0]
      const heights2 = [1, 2, 4, 5, 6, 7, 1, 1];
      heights2.fill(0, 4);
      console.log(heights2); // Resultado: [1, 2, 4, 5, 0, 0, 0, 0]
    

Outras Funções Importantes

Existem outras funções úteis no JavaScript:

  • reverse()
  • sort()
  • entries()
  • fill()
  • find()
  • flat()

Procure-as para explorar mais possibilidades.

Conclusão

O JavaScript é uma linguagem extensa, com muitas funções e conceitos. Dedique tempo para explorar a linguagem e bibliotecas como Lodash. O resultado será maior produtividade e código mais limpo.