# Conceptos básicos de JS: Array#filter

_Array#filter_, o `Array.prototype.filter`, es un método que poseen todos lo
arrays en JavaScript. Este método nos sirve para filter un array y obtener uno
nuevo, lo que en palabras más normales significa que vamos a recorrer un array y
aplicar una condición a cada uno de sus elementos y solo quedarnos con los que
pasen. Veamos un ejemplo:

```js
const numbers = [1, 2, 3];
const evens = numbers.filter(number => number % 2 === 0); // es par
console.log(evens); // [2]
```

Lo que hace Array#filter entonces es llamar la función que pasamos como
argumento una vez por cada elemento del array.

> _Nota_: Ya que Array#filter devuelve un nuevo array, es una mala práctica
> usarlo para modificar manualmente el array inicial o hacer algún otro efecto
> al recorrer el array, para eso es mejor usar Array#forEach.

Si queremos hacer lo mismo que Array#filter tendríamos que hacer algo similar a
esto:

```js
const numbers = [1, 2, 3];
const evens = [];

for (const number of numbers) {
  if (number % 2 === 0) evens.push(number);
}

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

Tendríamos que crear un nuevo array vacío, recorrer el primero e ir haciendo
Array#push de cada valor que pase nuestra condición

## Sintaxis

La sintaxis completa de la función es la siguiente

```js
const result = initial.filter(function callback(currentValue, index, array) {
  // Devuelve true o false para saber si debe quedarse o no
}, thisArg);
```

Array#filer recibe dos argumentos, una función `callback` y un valor,
cualquiera, que va a ser asignado como `this` del callback, en caso de usar
_arrow functions_ este valor no hace nada. El callback a su vez recibe tres
argumentos, la mayoría de las veces se suele usar solo el primero y algunas
veces el segundo, el primero es el valor actual por el que estamos pasando en la
iteración, el segundo es el índice dentro de nuestro array y el tercero es el
mismo array que estamos iterando.

Por último, la función devuelve un nuevo array con los resultados de haber
ejecutado `callback` una vez por cada elemento del array inicial.

## Implementando Array#filter a mano

Veamos ahora como crear nuestro propio Array#filter para entender mejor su
funcionamiento. Vamos a implementarlo como una función llamada `filter` cuyo
primer valor va a ser el `array` a filtear y después vamos a recibir el
`callback` y el valor de `this`.

```js
function filter(array, callback, thisArg) {
  const result = [];
  const boundCallback = thisArg ? callback.bind(thisArg) : callback;
  for (let index = 0; index < array.length; index++) {
    if (boundCallback(array[index], index, array)) result.push(array[index]);
  }
  return result;
}

const numbers = [1, 2, 3];
const evens = filter(numbers, number => number % 2 === 0);
console.log(evens); // [2,4,6]
```

¿Qué es lo que hicimos? Nuestra función recibe los tres argumentos que dijimos
antes, luego crea un array vacío llamado `result` y una constante llamada
`boundCallback` que en caso de que se haya definido `thisArg` es igual a hacer
Function#bind de `callback` con el valor de `thisArg` y en caso contrario es
igual a `callback`. Después iteramos el array inicial y hacemos `result.push` si
el valor que devuelve `callback` es `true`, al cual le pasamos el valor actual
del array, el índice y el array entero. Por último devolvemos el resultado.

## Casos de uso

Array#filter es usado un montón en JavaScript, especialmente cuando se trabaja
de una forma funcional y en combinación con otros métodos como
[Array#map](/articles/js-basics/array-prototype-filter). Es usado en React.js
para filtras listas de datos en elementos de React, por ejemplo:

```js
function List({ list, query }) {
  return (
    <ul>
      {list
        .filter(item => item.content.includes(query))
        .map(item => <Item key={item.id} {...item} />)
      }
    </ul>
  );
}

ReactDOM.render(
  <List list={[{ id: 1, content: "hola" }, { id: 2, content:  }]} query="hola" />,
  target
);
```

Este componente `List` usa Array#filter para filtrar según el contenido de cada
elemento y Array#map para transformar cada `item` que queda después del filtro
del array `list` en el elemento devuelto por el componente `Item` pasándole toda
la información de cada `item` al componente.

---

Fuera de React puede ser usado también para trabajar con listas de elementos del
DOM.

```js
const $selectList = document.querySelectorAll("select");
const values = Array.from($selectList)
  .map($select => $select.value)
  .filter(value => value !== "");
```

Lo que hace el ejemplo es obtener todos los `<select>` de una página lo que
devuelve un objeto NodeList, usando `Array.from` lo convertimos a un array y
usamos Array#map para obtener una lista (`values`) de los valores de cada
`<select>`, por último con Array#filter eliminamos los valores igual a un string
vacío, que podría ser considerado la opción por defecto.

## Palabras finales

Este método es muy útil y es usado a diario al trabajar con Arrays en
JavaScript. Si no lo habías usado antes te recomiendo probar varios ejemplos de
uso para familiarizarte, cuando lo hagas vas a querer usarlo siempre,
especialmente en combinación de Array#map y Array#reduce.

