Banner arrays in javascript
JavaScript

Por que Evitar Laços for no JavaScript: Usando Funções de Arrays com Eficácia

Descubra como transformar seu código JavaScript em algo mais limpo e expressivo, evitando o uso desnecessário de laços for.



No desenvolvimento em JavaScript, uma prática comum é o uso de laços for, for...in ou for...of para iterar sobre arrays. Embora esses laços sejam poderosos, existem formas mais expressivas e eficazes de manipular arrays. Neste post, vamos explorar funções de arrays que frequentemente substituem o uso de laços for. Além disso, vamos examinar as vantagens e desvantagens dessa abordagem e discutir quando o uso do for ainda é necessário.

Sumário

  1. Vantagens de Usar Funções de Arrays
  2. Funções de Arrays para Evitar for
    1. map() vs. for
    2. filter() vs. for
    3. reduce() vs. for
    4. every() vs. for
    5. some() vs. for
    6. find() vs. for
    7. includes() vs. for
  3. Quando Ainda Usar Laços for
  4. Conclusão
  5. Lista de Funções para Manipular Arrays

Vantagens de Usar Funções de Arrays

  1. Legibilidade e Expressividade: Funções como map e filter tornam o código mais claro, eliminando a necessidade de escrever a lógica de controle de um loop.
  2. Imutabilidade: Funções como filter, map e reduce criam novos arrays, evitando alterações no array original.
  3. Menos Código Boilerplate: Funções de array requerem menos código do que loops for, o que reduz a verbosidade.
  4. Poder Declarativo: Funções como every e some são mais declarativas, facilitando a compreensão da intenção do código.

Funções de Arrays para Evitar for

1. map() vs. for

Exemplo com map:

let numbers = [1, 2, 3];
let doubled = numbers.map(x => x \* 2);

console.log(doubled); // [2, 4, 6]

Equivalente com for:

let numbers = [1, 2, 3];
let doubled = [];

for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] \* 2);
}

console.log(doubled); // [2, 4, 6]

Vantagens:

  • Legibilidade: O map() é mais conciso e expressivo, deixando claro que a intenção é transformar cada item de um array.
  • Imutabilidade: O map() cria um novo array sem modificar o original.

2. filter() vs. for

Exemplo com filter:

let numbers = [1, 2, 3, 4];
let evens = numbers.filter((x) => x % 2 === 0);

console.log(evens); // [2, 4]

Equivalente com for:

let numbers = [1, 2, 3, 4];
let evens = [];

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    evens.push(numbers[i]);
  }
}

console.log(evens); // [2, 4]

Vantagens:

  • Legibilidade: O código com filter() é mais direto ao ponto, sem a necessidade de condicionais explícitas.
  • Imutabilidade: Garante que o array original não seja alterado.

3. reduce() vs. for

Exemplo com reduce:

let numbers = [1, 2, 3, 4];
let sum = numbers.reduce((acc, x) => acc + x, 0);

console.log(sum); // 10

Equivalente com for:

let numbers = [1, 2, 3, 4];
let sum = 0;

for (let i = 0; i < numbers.length; i++) {
  sum += numbers[i];
}

console.log(sum); // 10

Vantagens:

  • Conciso: O reduce() resume todo o processo de acumulação em uma única linha de código.
  • Sem variáveis externas: Não há necessidade de declarar variáveis adicionais fora do loop.

4. every() vs. for

Exemplo com every:
let numbers = [1, 2, 3, 4];
let allPositive = numbers.every((x) => x > 0);

console.log(allPositive); // true

Equivalente com for:

let numbers = [1, 2, 3, 4];
let allPositive = true;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] <= 0) {
    allPositive = false;
    break;
  }
}

console.log(allPositive); // true

Vantagem:

Com every(), o código é mais claro e elimina a necessidade de break para encerrar o loop.


5. some() vs. for

Exemplo com some:

let numbers = [1, 2, 3, 4];
let hasNegative = numbers.some((x) => x < 0);

console.log(hasNegative); // false

Equivalente com for:

let numbers = [1, 2, 3, 4];
let hasNegative = false;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] < 0) {
    hasNegative = true;
    break;
  }
}

console.log(hasNegative); // false

Vantagem:

O some() permite verificar a condição de maneira concisa e eficiente, sem a necessidade de variáveis intermediárias.


6. find() vs. for

Exemplo com find:

let numbers = [1, 2, 3, 4];
let firstEven = numbers.find((x) => x % 2 === 0);

console.log(firstEven); // 2

Equivalente com for:

let numbers = [1, 2, 3, 4];
let firstEven = null;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] % 2 === 0) {
    firstEven = numbers[i];
    break;
  }
}

console.log(firstEven); // 2

Vantagem:

find() expressa claramente a intenção de encontrar o primeiro elemento que atenda a uma condição, eliminando a necessidade de break.


7. includes() vs. for

Exemplo com includes:

let numbers = [1, 2, 3, 4];
let hasTwo = numbers.includes(2);

console.log(hasTwo); // true

Equivalente com for:

let numbers = [1, 2, 3, 4];
let hasTwo = false;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] === 2) {
    hasTwo = true;
    break;
  }
}

console.log(hasTwo); // true

Vantagem:

includes() é muito mais direto e claro ao verificar a presença de um elemento.


Quando Ainda Usar Laços for

Embora essas funções de array ofereçam uma maneira mais limpa de manipular dados, ainda há casos em que o uso de um laço for pode ser necessário:

  • Performance em Grandes Arrays: Em situações críticas de desempenho, especialmente ao lidar com arrays grandes, o for simples pode ser mais eficiente.

    const numbers = Array(1e6).fill(0).map((_, i) => i);
    
    console.time('for');
    let sumFor = 0;
    for (let i = 0; i < numbers.length; i++) {
      sumFor += numbers[i];
    }
    console.timeEnd('for');
    
    console.time('reduce');
    const sumReduce = numbers.reduce((acc, n) => acc + n, 0);
    console.timeEnd('reduce');
    

  • Controle Fino sobre Iterações: Quando você precisa de controle granular sobre o loop, como pular iterações ou sair de um loop aninhado, o for pode ser mais prático.

  • Operações Assíncronas: Para operações assíncronas em cada iteração, como o uso de await, o for pode ser mais adequado.

    async function fetchData() {
      let data = [url1, url2, url3];
    
      for (let i = 0; i < data.length; i++) {
        let result = await fetch(data[i]);
        console.log(result);
      }
    }
    
    fetchData();
    

Conclusão

O JavaScript oferece uma variedade de funções de arrays que podem simplificar significativamente seu código. Evitar laços for sempre que possível não apenas torna o código mais limpo e legível, mas também ajuda a evitar armadilhas comuns, como efeitos colaterais. No entanto, em casos específicos, os laços for ainda têm seu lugar, principalmente quando o desempenho ou o controle granular são importantes.

Lista de funções para manipular arrays

FunçãoDescrição
map()Transforma cada elemento de um array em um novo valor e retorna um novo array com esses valores.
filter()Cria um novo array com todos os elementos que passam no teste fornecido pela função.
reduce()Reduz o array a um único valor, acumulando os resultados da função fornecida.
reduceRight()Reduz o array da direita para a esquerda, acumulando os resultados da função fornecida.
forEach()Executa uma função fornecida uma vez para cada elemento do array, sem retornar valor.
every()Verifica se todos os elementos do array passam no teste implementado pela função fornecida.
some()Verifica se ao menos um elemento do array passa no teste implementado pela função fornecida.
find()Retorna o primeiro elemento do array que satisfaz o teste implementado pela função fornecida.
findIndex()Retorna o índice do primeiro elemento que satisfaz o teste implementado pela função fornecida.
findLast()Retorna o último elemento do array que satisfaz o teste implementado pela função fornecida.
findLastIndex()Retorna o índice do último elemento que satisfaz o teste implementado pela função fornecida.
includes()Verifica se o array contém um determinado valor e retorna true ou false.
indexOf()Retorna o primeiro índice no qual o valor especificado é encontrado, ou -1 se não for encontrado.
lastIndexOf()Retorna o último índice no qual o valor especificado é encontrado, ou -1 se não for encontrado.
push()Adiciona um ou mais elementos ao final do array e retorna o novo comprimento do array.
pop()Remove o último elemento de um array e o retorna.
shift()Remove o primeiro elemento de um array e o retorna.
unshift()Adiciona um ou mais elementos ao início do array e retorna o novo comprimento do array.
slice()Retorna uma cópia superficial de uma parte do array em um novo array, sem modificar o original.
splice()Altera o conteúdo de um array removendo, substituindo ou adicionando novos elementos.
concat()Junta dois ou mais arrays e retorna um novo array.
join()Junta todos os elementos de um array em uma string.
reverse()Inverte a ordem dos elementos de um array no local.
sort()Ordena os elementos do array no local e retorna o array.
fill()Preenche todos os elementos de um array com um valor estático.
copyWithin()Copia parte do array para outra localização dentro do mesmo array, sem alterar o tamanho.
flat()Achata arrays aninhados em um array.
flatMap()Mapeia cada elemento de um array e depois achata o resultado em um novo array.
keys()Retorna um novo iterador de array que contém as chaves de índice para cada elemento no array.
values()Retorna um novo iterador de array que contém os valores para cada elemento no array.
entries()Retorna um novo iterador de array que contém pares chave/valor para cada elemento no array.
at()Retorna o elemento no índice fornecido, permitindo o uso de índices negativos.
Array.from()Cria uma nova instância de array a partir de um objeto semelhante a um array ou iterável.
Array.of()Cria um novo array com os elementos passados como argumentos.
isArray()Verifica se um valor é um array.