Casi todo lo que harás con datos en el cliente es trabajar con listas: los productos que llegan de una API, las tareas de una aplicación, las filas de una tabla. Podrías recorrerlas siempre con for, pero los arrays traen métodos que dicen qué quieres obtener en lugar de cómo recorrer. Todos se basan en lo que ya sabes: reciben una función como argumento.
1 // Recorrer y buscar
Todos los métodos de esta unidad reciben un callback que se llama una vez por elemento, con tres argumentos: el elemento, su índice y el array completo. Casi siempre sólo usarás el primero.
const alumnos = [
{ nombre: 'Ana', nota: 8, curso: '2DAW' },
{ nombre: 'Luis', nota: 4, curso: '2DAW' },
{ nombre: 'Eva', nota: 9, curso: '2DAM' },
];
alumnos.forEach(a => console.log(a.nombre)); // recorre, no devuelve nada
alumnos.find(a => a.nota < 5); // { nombre: 'Luis', ... }
alumnos.findIndex(a => a.nombre === 'Eva'); // 2
alumnos.some(a => a.nota < 5); // true: al menos uno
alumnos.every(a => a.nota >= 5); // false: no todosfind devuelve el primer elemento que cumple la condición, o undefined si ninguno la cumple. some y every responden sí o no y dejan de recorrer en cuanto conocen la respuesta.
Para recorrer también existe for...of, que es la opción adecuada cuando necesitas salir antes con break o usar await dentro del bucle:
for (const alumno of alumnos) {
if (alumno.nota < 5) break;
console.log(alumno.nombre);
}2 // Filtrar, transformar y resumir
Los tres métodos más importantes devuelven un resultado nuevo sin tocar el array original:
| Método | El callback devuelve | El método devuelve |
|---|---|---|
filter |
true o false: ¿se queda este elemento? |
Array con los que pasan |
map |
El valor transformado | Array del mismo tamaño |
reduce |
El acumulado hasta ahora | Un único valor |
const aprobados = alumnos.filter(a => a.nota >= 5);
// [{ nombre: 'Ana', ... }, { nombre: 'Eva', ... }]
const nombres = alumnos.map(a => a.nombre);
// ['Ana', 'Luis', 'Eva']
const sumaNotas = alumnos.reduce((acumulado, a) => acumulado + a.nota, 0);
// 21reduce es el que más cuesta al principio. Léelo así: empieza con el valor inicial (0), y en cada vuelta el callback recibe lo acumulado y el elemento actual, y devuelve el nuevo acumulado. En la primera vuelta devuelve 0 + 8; en la segunda, 8 + 4; en la tercera, 12 + 9.
Elige el método por lo que quieres obtener: un subconjunto, filter; una lista transformada, map; un solo elemento, find; un único valor calculado a partir de todos, reduce; nada, sólo efectos, forEach.
3 // Métodos que modifican el array
No todos los métodos son igual de respetuosos. Algunos modifican el array sobre el que se llaman, y eso importa por lo que viste en la unidad de referencias: si ese array se usa en otra parte, también cambia allí.
| Modifican el original | No lo modifican |
|---|---|
push, pop, shift, unshift |
map, filter, reduce, find |
splice |
slice, concat |
sort, reverse |
toSorted, toReversed |
fill |
toSpliced, with |
Las versiones con to (toSorted, toReversed, toSpliced) y with son recientes y hacen lo mismo que sus equivalentes, pero devolviendo un array nuevo.
sort() sin argumentos ordena como texto, incluso si todos los elementos son números: [10, 9, 1].sort() da [1, 10, 9]. Pasa siempre una función de comparación: (a, b) => a - b para orden ascendente, (a, b) => b - a para descendente, o (a, b) => a.nombre.localeCompare(b.nombre) para textos.
4 // Encadenar métodos
Como filter y map devuelven arrays, puedes llamar al siguiente método directamente sobre el resultado. Así, un procesamiento de varios pasos se lee de arriba abajo:
Una tienda tiene esta lista y quiere mostrar el total con IVA de los productos disponibles:
const productos = [
{ nombre: 'Cable', precio: 10, stock: 3 },
{ nombre: 'Ratón', precio: 25, stock: 0 },
{ nombre: 'Funda', precio: 5, stock: 12 },
{ nombre: 'Teclado', precio: 40, stock: 1 },
];- Quedarse con los disponibles:
.filter(p => p.stock > 0)deja Cable, Funda y Teclado. - Calcular el precio con IVA de cada uno:
.map(p => p.precio * 1.21)da[12.1, 6.05, 48.4]. - Sumarlos:
.reduce((total, precio) => total + precio, 0)da66.55. - Redondear para mostrarlo: con precios en coma flotante no hay garantía de que el resultado salga exacto (recuerda
0.1 + 0.2), así que.toFixed(2)lo convierte en el texto'66.55'con dos decimales fijos.
const total = productos
.filter(p => p.stock > 0)
.map(p => p.precio * 1.21)
.reduce((suma, precio) => suma + precio, 0)
.toFixed(2);productos sigue intacto con sus cuatro elementos. Cada línea de la cadena responde a una pregunta: cuáles, qué valor de cada uno y cómo se combinan.5 // Para practicar
Resuelve cada ejercicio primero con un bucle y después con el método de array adecuado. Cada ejercicio trae el enunciado en los comentarios del código.
Suma, máximo, mínimo y mediatraining-daw-sv/modulo-00/06-metodos-de-array/01_math_arrayInsertar sin duplicar ni modificartraining-daw-sv/modulo-00/06-metodos-de-array/02_insert_if_not_existsPilotos con map, filter y reducetraining-daw-sv/modulo-00/06-metodos-de-array/03_iteratorsAutoevaluación
¿Por qué const nombres = alumnos.forEach(a => a.nombre) deja nombres en undefined, y qué método habría que usar?
forEach sólo recorre; no construye nada. Ejecuta la función para cada elemento y siempre devuelve undefined, ignorando lo que devuelva el callback. Para obtener un array nuevo con un valor por elemento se usa map.[10, 9, 1].sort() devuelve [1, 10, 9]. ¿Qué está haciendo sort y cómo se corrige?
sort ordena como texto. Convierte cada elemento en cadena y compara carácter a carácter, y '10' va antes que '9' porque '1' va antes que '9'. Con (a, b) => a - b se ordena numéricamente.En un reduce para sumar precios, ¿qué papel tienen el acumulador y el valor inicial?
reduce usa el primer elemento y falla con arrays vacíos.