# map(), filter() e reduce() em JavaScript

> Domine map, filter e reduce em JavaScript. Aprenda métodos funcionais essenciais de arrays para transformar e processar dados elegantemente. Programe melhor!

URL: https://dpw.dev/javascript/map-filter-reduce-javascript/  
Publicado em: 2016-07-25  
Categoria: javascript  
Tags: basico-da-web  
Autor: Tárcio Zemel

Já alguns anos, JavaScript chegou com métodos de manipulação de array mais voltados à **programação funcional**. Neste artigo, conheça a utilidade das funções **`map()`**, **`filter()`** e **`reduce()`** através de exemplos de códigos, parâmetros e casos de uso.

> Artigo baseado em [JavaScript´s Map, Reduce, and Filter](https://danmartensen.svbtle.com/javascripts-map-reduce-and-filter).

Como programadores, construímos e manipulamos arrays de números, strings, booleanos e objetos quase todos os dias. Nós os usamos para processar números, coletar objetos, dar split em string, pesquisar, ordenar e muito mais. Mas qual é a melhor maneira de trabalhar com arrays? Tradicionalmente, tem sido usar loops para fazer a iteração nos elementos usando índice.

Em 2011, chegou em JavaScript `map()`, `filter()` e `reduce()` como alternativas poderosas tanto para se trabalhar com valores cumulativos, quanto para criar subconjuntos com base em condições. Estes métodos são úteis para reduzir a complexidade, trabalhar sem "efeitos colaterais" e, muitas vezes, tornar o código mais legível.

## Desvantagens do loop

Digamos que se está trabalhando em uma correção de bug e, vagueando por 1000 linhas de código JavaScript, eis que o seguinte loop se apresenta:

```javascript
for ( var i = 0; i < array.length; i++ ) {
    if ( array.indexOf( array[ i ] ) === i ) {
        models.push(array[ i ] );
    }
}

```

Foi possível ver que o loop serve para criar um novo array com elementos não duplicados no original. Mas, para descobrir isso, foi necessária uma análise em 5 etapas:

| Código | Significado |
| --- | --- |
| `var i = 0` | Começa à esquerda do array |
| `i < array.length` | Termina à direita |
| `i++` | Incremento de 1 em 1 |
| `array.indexOf( array[ i ] ) === i` | Se o valor é de primeira instância no array, vai coincidir com o índice (isso significa que se está verificando uma duplicata) |
| `models.push(...)` | `models` deve ser uma lista, mas quais dados ali constam? Quais são seus tipos de dados? É preciso procurar um arquivo "models". Enxaguar. Repetir. |

É necessário verificar 5 pedaços de informações para determinar o que está acontecendo. E este é um único loop!

## Uma abordagem funcional

Este mesmo objetivo poderia ser escrito usando o método `filter()` de JavaScript da seguinte maneira:

```javascript
var uniqueProducts = array.filter( function( elem, i, array ) {
    return array.indexOf( elem ) === i;
} );

```

Simples e elegante.

Visto que `filter()` comunica comportamento de código, então é possível saber exatamente o objetivo da função. Em comparação com a abordagem de looping acima:

- Checar #1, #2 e #3 é desnecessário, já que `filter()` faz isso automaticamente.
- #4 é o mesmo, mas sem o adicional de checagem do bloco `if`.
- Um grande obstáculo foi #5 -- lembra-se do número de questões que ele suscitava? `map()`, `filter()` e `reduce()` resolvem esse tipo de problema ao não dependerem de código fora dos callbacks.

No final das contas, `map()`, `filter()` e `reduce()` fazem do código menos complexo, sem efeitos colaterais e, freqüentemente, mais legível.

## `map()`

[Vídeo no YouTube](https://www.youtube.com/watch?v=o8fdyYZDKA0)

**Use `map()` quando**: é preciso traduzir/mapear todos os elementos em um array para outro conjunto de valores.

Exemplo: converter temperatura de Fahrenheit para Celsius.

```javascript
var fahrenheit = [ 0, 32, 45, 50, 75, 80, 99, 120 ];

var celcius = fahrenheit.map( function( elem ) {
    return Math.round( ( elem - 32 ) * 5 / 9 );
} ); 

// ES6
// fahrenheit.map( elem => Math.round( ( elem - 32 ) * 5 / 9 ) );

celcius //  [ -18, 0, 7, 10, 24, 27, 37, 49 ]

```

**O que `map()` faz**: percorre o array da esquerda para a direita invocando uma função de retorno em cada elemento com parâmetros. Para cada chamada de retorno, o valor devolvido se torna o elemento do novo array. Depois que todos os elementos foram percorridos, `map()` retorna o novo array com todos os elementos "traduzidos".

Parâmetros:

```javascript
array.map( function( elem, index, array ) {
    ...
}, thisArg );

```

| Parâmetro | Significado |
| --- | --- |
| `elem` | Valor do elemento |
| `index` | Índice em cada iteração, da esquerda para a direita |
| `array` | Array original invocando o método |
| `thisArg` | (opcional) Objeto que será referenciado como `this` no callback |

## `filter()`

[Vídeo no YouTube](https://www.youtube.com/watch?v=sDXkvb_rVxA)

**Use `filter()` quando**: é preciso remover elementos indesejados com base em alguma(s) condição(ões).

Exemplo: remover elementos duplicados de um array.

```javascript
var uniqueArray = array.filter( function( elem, index, array ) {
    return array.indexOf( elem ) === index;
} );

// ES6
// array.filter( ( elem, index, arr ) => arr.indexOf( elem ) === index );

```

**O que `filter()` faz**: como `map()`, `filter()` percorre o array da esquerda para a direita invocando uma função de retorno em cada elemento. O valor retornado deve ser um booleano que indica se o elemento será mantido ou descartado. Depois de todos os elementos terem sido analisados, `filter()` retorna um novo array com todos os elementos que retornaram como verdadeiro.

Parâmetros (os mesmo que `map()`):

```javascript
array.filter( function( elem, index, array ) {
    ...
}, thisArg );

```

| Parâmetro | Significado |
| --- | --- |
| `elem` | Valor do elemento |
| `index` | Índice em cada iteração, da esquerda para a direita |
| `array` | Array original invocando o método |
| `thisArg` | (opcional) Objeto que será referenciado como `this` no callback |

## `reduce()`

[Vídeo no YouTube](https://www.youtube.com/watch?v=dckGT8Rts-4)

**Use `reduce()` quando**: é preciso encontrar um valor cumulativo ou concatenado com base em elementos de todo o array.

Exemplo: soma de lançamentos de foguetes orbitais no período de 1 ano.

```javascript
var rockets = [
    { country:'Russia', launches:32 },
    { country:'US', launches:23 },
    { country:'China', launches:16 },
    { country:'Europe(ESA)', launches:7 },
    { country:'India', launches:4 },
    { country:'Japan', launches:3 }
];

var sum = rockets.reduce( function( prevVal, elem ) {
    return prevVal + elem.launches;
}, 0 );

// ES6
// rockets.reduce( ( prevVal, elem ) => prevVal + elem.launches, 0 ); 

sum // 85

```

> **Dica:** Se ficou com dúvidas na notação de `rockets`, [leia o artigo sobre JSON](/javascript/json-javascript-object-notation/).

**O que `reduce()` faz**: como `map()`, `reduce()` percorre o array da esquerda para a direita invocando uma função de retorno em cada elemento. O valor retornado é o valor acumulado passado de callback para callback. Depois de todos os elementos terem sido avaliados, `reduce()` retorna o valor acumulado/concatenado.

Parâmetros:

```javascript
array.reduce( function( prevVal, elem, index, array ) {
    ...
}, initialValue );

```

| Parâmetro | Significado |
| --- | --- |
| `prevVal` | Valor cumulado retornado em cada iteração |
| `elem` | Valor do elemento |
| `index` | Índice em cada iteração, da esquerda para a direita |
| `array` | Array original invocando o método |
| `initialValue` | (opcional) Objeto usado como primeiro argumento na primeira iteração (mais à esquerda) |

## Conclusão sobre `map()`, `filter()` e `reduce()` em JavaScript

Como informações extras sobre `map()`, `filter()` e `reduce()`, dá-se que:

- Cada um deles é um método no objeto de protótipo (prototype) Array
- Alterar um elemento no parâmetro `array` em qualquer callback persistirá através de todos os callbacks restantes, mas não apresentará quaisquer efeitos no array retornado
- Funções de callback são invocadas nos índices com qualquer valor, até `undefined`, mas não valores excluídos ou que nunca tiveram um valor atribuído

> **Dica:** Caso tenha dúvidas sobre a sintaxe de ECMAScript 6, conheça o repo [es6features](https://github.com/webfatorial/es6features), com resumo das principais funcionalidades de ES6 com exemplos de códigos.

Importante ressaltar, também, que `map()`, `filter()` e `reduce()` não vieram para substituir loops que, definitivamente, ainda têm seu lugar em diversas situações -- como, por exemplo, ao se trabalhar com grandes arrays (mais de 1k elementos) ou quando é preciso parar a iteração se determinada(s) condição(ões) for(em) atendida(s) (`break`).

Para continuar a conhecer as principais funções de array JavaScript, leia também nosso artigo [every(), some(), find() e includes() em JavaScript](/javascript/every-some-find-includes-javascript/).

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
