Así como tenemos un conjunto de métodos para realizar sobre variables que sean
¿Qué son las Array functions?
Básicamente, son métodos que tiene cualquier variable que sea de tipo
Estas son las Array functions que podemos encontrarnos en Javascript:
Método | Descripción |
---|---|
.forEach(ƒ) | Ejecuta la función definida en ƒ por cada uno de los elementos del array. |
Comprobaciones | |
.every(ƒ) | Comprueba si todos los elementos del array cumplen la condición de ƒ . |
.some(ƒ) | Comprueba si al menos un elemento del array cumple la condición de ƒ . |
Transformadores y filtros | |
.map(ƒ) | Construye un array con lo que devuelve ƒ por cada elemento del array. |
.filter(ƒ) | Filtra un array y se queda sólo con los elementos que cumplen la condición de ƒ . |
.flat(level) | Aplana el array al nivel level indicado. |
.flatMap(ƒ) | Aplana cada elemento del array, transformándolo según ƒ . Equivale a .map().flat(1) . |
Búsquedas | |
.findIndex(ƒ) | Devuelve la posición del elemento que cumple la condición de ƒ . |
.find(ƒ) | Devuelve el elemento que cumple la condición de ƒ . |
.findLastIndex(ƒ) | Idem a findIndex() , pero empezando a buscar desde el último elemento al primero. |
.findLast(ƒ) | Idem a find() , pero empezando a buscar desde el último elemento al primero. |
Acumuladores | |
.reduce(ƒ, initial) | Ejecuta ƒ con cada elemento (de izq a der), acumulando el resultado. |
.reduceRight(ƒ, initial) | Idem al anterior, pero en orden de derecha a izquierda. |
A grandes rasgos, a cada uno de estos métodos se les pasa una función callback que se ejecutará por cada uno de los elementos que contiene el array. Empecemos por forEach()
, que es quizás el más sencillo de todos.
Bucles .forEach()
Como se puede ver, el método forEach()
no devuelve nada y espera que se le pase por parámetro una
const letters = ["a", "b", "c", "d"];
// Con funciones por expresión
const f = function () {
console.log("Un elemento.");
};
letters.forEach(f);
// Con funciones anónimas
letters.forEach(function () {
console.log("Un elemento.");
});
// Con funciones flecha
letters.forEach(() => console.log("Un elemento."));
Sin embargo, este ejemplo no tiene demasiada utilidad. A la
- Si se le pasa un primer parámetro, este será el elemento del array.
- Si se le pasa un segundo parámetro, este será la posición en el array.
- Si se le pasa un tercer parámetro, este será el array en cuestión.
Veamos un ejemplo:
const letters = ["a", "b", "c", "d"];
letters.forEach((element) => console.log(element));
// Devuelve 'a' / 'b' / 'c' / 'd'
letters.forEach((element, index) => console.log(element, index));
// Devuelve 'a' 0 / 'b' 1 / 'c' 2 / 'd' 3
letters.forEach((element, index, array) => console.log(array[0]));
// Devuelve 'a' / 'a' / 'a' / 'a'
En este ejemplo, he nombrado element
al parámetro que hará referencia al elemento, index
al parámetro que hará referencia al índice (posición del array) y array
al parámetro que hará referencia al propio array en cuestión. En algunos ejemplos los abreviaré como (e, i, a)
, por su inicial. Aún así, el usuario puede ponerle a estos parámetros el nombre que prefiera.
Por ejemplo, una buena estrategia sería utilizar letters
(plural) para el array y letter
(singular) en lugar de element
para el elemento que se va recorriendo. Como se puede ver, realmente forEach()
es otra forma de hacer un bucle (sobre un array), sin tener que recurrir a bucles tradicionales como for
o while
.
Aunque no aparece en la tabla anterior, al método
forEach()
se le puede pasar un segundo parámetroarg
, que representa el valor que sobreescribiría a la palabra clavethis
en el código dentro de la función callback. De necesitar esta funcionalidad, no podrías utilizar las funciones flecha, ya que elthis
no tiene efecto en ellas.
Comprobaciones
Existen dos métodos para realizar comprobaciones: el método .every()
y el método .some()
. Ambos métodos evaluan los elementos del array y devuelven siempre un
El método .every()
(Todos)
El método every()
permite comprobar si todos y cada uno de los elementos de un array cumplen la condición que se especifique en la
const letters = ["a", "b", "c", "d"];
letters.every((letter) => letter.length === 1); // true
En este caso, la magia está en el callback. La condición es que la longitud de cada elemento 1
. Si dicha función devuelve true
, significa que cumple la condición, si devuelve false
, no la cumple. Por lo tanto, si todos los elementos del array devuelven true
, entonces every()
devolverá true
.
Si expandimos el ejemplo anterior a un código más detallado, tendríamos el siguiente ejemplo equivalente, que quizás sea más comprensible para entenderlo:
const letters = ["a", "b", "c", "d"];
// Esta función se ejecuta por cada elemento del array
const condition = function (letter) {
// Si el tamaño del elemento (string) es igual a 1
if (letter.length == 1) {
return true;
}
else {
return false;
}
};
// Si todos los elementos devuelven true, devuelve true
letters.every(condition); // true
El método .some()
(Al menos uno)
De la misma forma que el método anterior sirve para comprobar si todos los elementos del array cumplen una determinada condición, con some()
podemos comprobar si al menos uno de los elementos del array, cumplen dicha condición definida por el callback.
const letters = ["a", "bb", "c", "d"];
letters.some((element) => element.length == 2); // true
Observa que en este ejemplo, el método some()
devuelve true
porque existe al menos un elemento del array con una longitud de 2
caracteres.
Transformadores y filtros
En esta categoría encontraremos varios métodos que realizan operaciones de transformación o de filtrado, es decir, nos creamos una variación de los elementos de un array (transformación) o filtramos y nos quedamos con una pequeña parte de un array (filtros). Vamos a explicar cada uno de ellos.
El método .map()
El método map()
es un método muy potente y útil para trabajar con arrays, puesto que su objetivo es devolver un nuevo array donde cada uno de sus elementos será lo que devuelva la función callback por cada uno de los elementos del array original:
const names = ["Ana", "Pablo", "Pedro", "Pancracio", "Heriberto"];
const nameSizes = names.map((name) => name.length);
nameSizes; // Devuelve [3, 5, 5, 9, 9]
Observa que el array devuelto por map()
es nameSizes
, y cada uno de los elementos que lo componen, es el número devuelto por el callback (name.length), que no es otra cosa sino el tamaño de cada
Este método nos permite hacer multitud de operaciones, ya que donde devolvemos name.length
podriamos devolver el propio
El método .filter()
El método filter()
nos permite filtrar los elementos de un array y devolver un nuevo array con sólo los elementos que queramos. Para ello, utilizaremos la función callback para establecer una condición que devuelve true
sólo en los elementos que nos interesen:
const names = ["Ana", "Pablo", "Pedro", "Pancracio", "Heriberto"];
const filteredNames = names.filter((name) => name.startsWith("P"));
filteredNames; // Devuelve ['Pablo', 'Pedro', 'Pancracio']
En este ejemplo, filtramos sólo los elementos en los que su primera letra sea P
. Por lo tanto, la variable filteredNames
será un array con sólo esos elementos.
Ten en cuenta que si ningún elemento cumple la condición, filter()
devuelve un
El método .flatMap()
Un método que puede resultar interesante es .flat(level)
level
indicado por parámetro.
Por ejemplo, considera el siguiente array:
const values = [10, 15, 20, [25, 30], 35, [40, 45, [50, 55], 60]];
values.flat(0); // [10, 15, 20, [25, 30], 35, [40, 45, [50, 55], 60]];
values.flat(1); // [10, 15, 20, 25, 30, 35, 40, 45, [50, 55], 60];
values.flat(2); // [10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60];
// Idem al anterior, pero si hubieran más niveles los aplanaría todos
values.flat(Infinity);
Observa que el array values
tiene 6 elementos, donde el cuarto elemento y el sexto elemento son arrays anidados. En el array del cuarto elemento hay dos números, pero en el array del sexto elemento hay a su vez un array con cuatro elementos donde su tercer elemento es nuevamente otro array. Estaríamos hablando de que el array values
tiene arrays hasta un nivel 3.
Con .flat()
podemos indicar hasta que nivel queremos «aplanarlo».
Sin embargo, este método .flat()
no pertenece a los métodos que estamos repasando. Sin embargo, es la base del método .flatMap(ƒ)
, que si tiene la misma filosofía que el resto de métodos. Funciona de forma muy parecida al método .map(ƒ)
, aplanando un nivel y transformando cada elemento del array, según la función pasada por parámetro. Es decir, el método .flatMap(ƒ)
es el equivalente a realizar la operación .map(ƒ).flat(1)
:
const values = [10, 15, 20, [25, 30], 35, [40, 45, [50, 55], 60]];
values.flatMap(element => Array.isArray(element) ? element.length : 1 );
// [1, 1, 1, 2, 1, 4]
El ejemplo anterior, realiza una .flatMap()
por la estructura values
. En primer lugar, recorre cada uno de los elementos mediante un map()
para transformarlos: si son un array, devuelve su cantidad de elementos, si no es un array, devuelve 1
. Finalmente, si el array resultante tuviera algún array entre sus elementos (que en este caso es imposible), le aplicaría un flat(1)
.
Búsquedas
Otra tarea habitual y necesaria es la de realizar búsquedas de elementos en un array. Mediante los siguientes métodos podemos realizar búsquedas de elementos concretos, ya sea buscando desde el principio o desde el final, así como queriendo quedarnos con el elemento buscado o la posición en el array del elemento buscado.
El método .find()
y .findIndex()
Dentro de las Array functions, existen dos métodos interesantes: find()
findIndex()
const names = ["Ana", "Pablo", "Pedro", "Pancracio", "Heriberto"];
names.find((name) => name.length == 5); // 'Pablo'
names.findIndex((name) => name.length == 5); // 1
La condición que hemos utilizado en este ejemplo es buscar el elemento que tiene 5
carácteres de longitud. Al buscarlo en el array original, el primero que encontramos es Pablo
, puesto que find()
devolverá 'Pablo' y findIndex()
devolverá 1
, que es la segunda posición del array donde se encuentra.
En el caso de no encontrar ningún elemento que cumpla la condición, find()
devolverá findIndex()
, que debe devolver un -1
.
El método .findLast()
y .findLastIndex()
De la misma forma, tenemos findLastIndex()
y findLast()
, que son las funciones equivalentes a findIndex()
y find()
, pero buscando elementos desde derecha a izquierda, en lugar de izquierda a derecha:
const names = ["Ana", "Pablo", "Pedro", "Pancracio", "Heriberto"];
names.findLast((name) => name.length == 5); // 'Pedro'
names.findLastIndex((name) => name.length == 5); // 2
En este caso, en lugar de encontrarnos a Pablo
(posición 1), el primer elemento que tiene 5 carácteres, como va buscando de derecha a izquierda, el primero que encuentra es Pedro
(posición 2).
Acumuladores
Por último, los acumuladores nos permiten realizar tareas por cada elemento del array, acumulando valores para hacerles una modificación en cada iteración. Los explicamos más detalladamente a continuación.
El método .reduce()
Por último, nos encontramos con una pareja de métodos denominados reduce()
y reduceRight()
. Ambos métodos se encargan de recorrer todos los elementos del array, e ir acumulando sus valores (o alguna operación diferente) y sumarlo todo, para devolver su resultado final.
En este par de métodos, encontraremos una primera diferencia en su función callback, puesto que en lugar de tener los clásicos parámetros opcionales (element, index, array)
que hemos utilizado hasta ahora, tiene (first, second, iteration, array)
, que funciona de forma muy similar, pero adaptado a este tipo de acumuladores.
En la primera iteración, first
contiene el valor del primer elemento del array y second
del segundo. En siguientes iteraciones, first
es el acumulador que contiene lo que devolvió el callback en la iteración anterior, mientras que second
es el siguiente elemento del array, y así sucesivamente. Veamos un ejemplo para entenderlo:
const numbers = [95, 5, 25, 10, 25];
numbers.reduce((first, second) => {
console.log(`F=${first} S=${second}`);
return first + second;
});
// F=95 S=5 (1ª iteración: elemento 1: 95 + elemento 2: 5) = 100
// F=100 S=25 (2ª iteración: 100 + elemento 3: 25) = 125
// F=125 S=10 (3ª iteración: 125 + elemento 4: 10) = 135
// F=135 S=25 (4ª iteración: 135 + elemento 5: 25) = 160
// Finalmente, devuelve 160
El método .reduceRight()
Gracias a esto, podemos utilizar el método reduce()
como acumulador de elementos de izquierda a derecha y reduceRight()
como acumulador de elementos de derecha a izquierda. Veamos un ejemplo de cada uno, realizando una resta en lugar de una suma:
const numbers = [95, 5, 25, 10, 25];
numbers.reduce((first, second) => first - second);
// 95 - 5 - 25 - 10 - 25. Devuelve 30
numbers.reduceRight((first, second) => first - second);
// 25 - 10 - 25 - 5 - 95. Devuelve -110
Parámetro inicial
Es posible indicar un segundo parámetro opcional en el .reduce()
. Este parámetro es el valor inicial que quieres tomar en el reduce, lo que puede facilitar bastante la implementación. Observa que en el primer ejemplo anterior, se realizan 4 iteraciones. Sin embargo, al indicar este valor inicial de cero se realizan 5 iteraciones:
const numbers = [95, 5, 25, 10, 25];
numbers.reduce((accumulator, nextElement) => {
console.log(`F=${accumulator} S=${nextElement}`);
return accumulator + nextElement;
}, 0);
// F=0 S=95 (iteración inicial): 0 + elemento 1: 95) = 95
// F=95 S=5 (1ª iteración: elemento 1: 95 + elemento 2: 5) = 100
// F=100 S=25 (2ª iteración: 100 + elemento 3: 25) = 125
// F=125 S=10 (3ª iteración: 125 + elemento 4: 10) = 135
// F=135 S=25 (4ª iteración: 135 + elemento 5: 25) = 160
// Finalmente, devuelve 160
Como se puede ver, hay una iteración 0 extra que es la que toma el valor inicial indicado, junto al primer elemento del array. Luego, sigue iterando con el resto de elementos.