Inspirado por escrever esta resposta, acabei expandindo mais tarde e escrevendo uma postagem no blog que tratava disso com detalhes cuidadosos. Recomendo verificar isso se você quiser desenvolver um entendimento mais profundo de como pensar sobre esse problema - tento explicá-lo peça por peça e também fornecer uma comparação JSperf no final, passando por considerações de velocidade.
Dito isso, o tl; dr é o seguinte: para realizar o que você está pedindo (filtragem e mapeamento em uma chamada de função), você usariaArray.reduce()
.
No entanto, a abordagem mais legível e (menos importante) geralmente significativamente mais rápida 2 é usar apenas o filtro e o mapa encadeados:
[1,2,3].filter(num => num > 2).map(num => num * 2)
O que se segue é uma descrição de como Array.reduce()
funciona e como pode ser usado para filtrar e mapear em uma iteração. Novamente, se isso estiver muito condensado, eu recomendo fortemente que você veja a postagem do blog no link acima, que é uma introdução muito mais amigável com exemplos claros e progressão.
Você fornece a reduzir um argumento que é uma função (geralmente anônima).
Essa função anônima leva dois parâmetros - um (como as funções anônimas passadas para map / filter / forEach) é o iteratário a ser operado. Há outro argumento para a função anônima passada reduzir, no entanto, que essas funções não aceitam, e é o valor que será passado entre as chamadas de função, geralmente referido como memo .
Observe que enquanto Array.filter () recebe apenas um argumento (uma função), Array.reduce () também assume um segundo argumento importante (embora opcional): um valor inicial para 'memo' que será passado para a função anônima como seu primeiro argumento e, subsequentemente, pode ser alterado e transmitido entre as chamadas de função. (Se não for fornecido, então 'memo' na primeira chamada de função anônima será, por padrão, o primeiro iteratário, e o argumento 'iteratário' será, na verdade, o segundo valor na matriz)
Em nosso caso, passaremos um array vazio para iniciar e, em seguida, escolheremos se injetamos nosso iteratê em nosso array ou não com base em nossa função - este é o processo de filtragem.
Por fim, retornaremos nosso 'array em andamento' em cada chamada de função anônima e reduzir pegará esse valor de retorno e o passará como um argumento (chamado memo) para sua próxima chamada de função.
Isso permite que o filtro e o mapa ocorram em uma iteração, reduzindo nosso número de iterações necessárias pela metade - apenas fazendo o dobro de trabalho em cada iteração, então nada é realmente salvo além de chamadas de função, que não são tão caras em javascript .
Para uma explicação mais completa, consulte os documentos do MDN (ou minha postagem referenciada no início desta resposta).
Exemplo básico de uma chamada Reduce:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
if (iteratee > 1) {
memo.push(iteratee * 2);
}
return memo;
}, initialMemo)
console.log(array)
versão mais sucinta:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Observe que o primeiro iteratee não era maior que um e, portanto, foi filtrado. Observe também o initialMemo, nomeado apenas para deixar clara sua existência e chamar a atenção para ele. Mais uma vez, ele é passado como 'memo' para a primeira chamada de função anônima e, em seguida, o valor retornado da função anônima é passado como o argumento 'memo' para a próxima função.
Outro exemplo do caso de uso clássico para memo seria retornar o menor ou o maior número em um array. Exemplo:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
Um exemplo de como escrever sua própria função de redução (isso geralmente ajuda a entender funções como essas, eu acho):
test_arr = [];
test_arr.my_reducer = function(reduceFunc, initialMemo) {
const initialMemoIsIndexZero = arguments.length < 2;
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
memo = reduceFunc(memo, this[i]);
}
return memo;
}
A implementação real permite acesso a coisas como o índice, por exemplo, mas espero que isso ajude você a ter uma noção descomplicada de sua essência.