Unidad 12 · Lecciones 088-095
Array Methods
Ya sabes recorrer un arreglo a mano. Ahora vas a aprender los metodos que hacen el trabajo pesado por ti: buscar, filtrar, sumar, comprobar y combinar, cada uno en una sola linea. Es lo que hay detras de los buscadores con filtros de Amazon o Airbnb.
🎯 Objetivo de aprendizaje
Al terminar sabras elegir y usar el array method adecuado para comprobar si algo existe, encontrar su posicion, filtrar por criterios, acumular un total y unir arreglos, sin escribir bucles manuales.
12.1 El punto de partida
Toda la unidad trabaja con estos dos arreglos, que representan los dos escenarios que encontraras siempre: un arreglo plano y un arreglo de objetos.
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo'];
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Audifonos', precio: 300 },
{ nombre: 'Teclado', precio: 400 },
{ nombre: 'Celular', precio: 700 }
];
💡 El patron que comparten todos
Casi todos estos metodos siguen la misma forma:
arreglo.metodo(elemento => condicion). Reciben una arrow function
(Unidad 9) a la que se le pasa automaticamente cada elemento. Cuando el cuerpo es de una linea,
el return es implicito y los parentesis del parametro sobran.
12.2 ¿Existe este valor? includes y some
La forma manual, para comparar
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo'];
meses.forEach(mes => {
if (mes === 'Enero') {
console.log('Enero si existe');
}
});
.includes() — solo para arreglos planos
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo'];
console.log(meses.includes('Enero')); // true
console.log(meses.includes('Diciembre')); // false
⚠ La limitacion de includes
Funciona con arreglos de valores simples. No sirve para arreglos de objetos, porque no puede saber por que propiedad quieres buscar.
.some() — sirve para los dos casos
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 700 }
];
// Version larga, para entenderla
const existe = carrito.some(function(producto) {
return producto.nombre === 'Celular';
});
// Version corta con arrow function y return implicito
const existe2 = carrito.some(producto => producto.nombre === 'Celular');
const noExiste = carrito.some(producto => producto.nombre === 'Monitor curvo');
console.log(existe); // true
console.log(existe2); // true
console.log(noExiste); // false
const meses = ['Enero', 'Febrero', 'Marzo'];
console.log(meses.some(mes => mes === 'Febrero')); // true
💡 Cual usar
Ambos devuelven true o false. includes es mas corto pero
solo vale para valores simples; some vale para todo. Con arreglos de objetos,
siempre some.
12.3 ¿En que posicion esta? findIndex
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo'];
const indice = meses.findIndex(mes => mes === 'Abril');
console.log(indice); // 3
const noExiste = meses.findIndex(mes => mes === 'Diciembre');
console.log(noExiste); // -1
💡 El -1 otra vez
Igual que indexOf en los strings (Unidad 3), findIndex devuelve
-1 cuando no encuentra nada. Por eso se suele comprobar asi:
const meses = ['Enero', 'Febrero', 'Marzo'];
const indice = meses.findIndex(mes => mes === 'Diciembre');
if (indice >= 0) {
console.log(`Encontrado en la posicion ${indice}`);
} else {
console.log('No se encontro');
}
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Audifonos', precio: 100 }
];
const indice = carrito.findIndex(producto => producto.precio === 100);
console.log(indice); // 1 <-- solo el PRIMERO que coincide
⚠ Solo devuelve el primero
Aunque haya dos productos a 100, findIndex se detiene en el primero. Si necesitas
todos los que cumplan la condicion, el metodo es filter (seccion 12.5).
12.4 reduce: de muchos valores a uno solo
Su nombre asusta y su definicion oficial («funcion reductora») no ayuda. En la practica es simple: toma muchos datos y los reduce a un unico resultado. El caso tipico: el total del carrito.
La forma manual
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 700 }
];
let total = 0;
carrito.forEach(producto => total += producto.precio);
console.log(`Total a pagar: ${total}`);
Con reduce
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 700 }
];
const resultado = carrito.reduce(
(total, producto) => total + producto.precio, // que hacer en cada vuelta
0 // valor inicial
);
console.log(`Total a pagar: ${resultado}`);
⚠ reduce es distinto a los demas
Todos los metodos anteriores reciben el elemento actual como primer parametro.
reduce no: el primero es el acumulador (lo que llevas sumado) y el
elemento actual es el segundo. Es la causa habitual de confusion.
Que hace cada parte
| Elemento | Que es |
|---|---|
total | El acumulador: el valor que se va arrastrando de una vuelta a la siguiente. |
producto | El elemento actual del arreglo. |
total + producto.precio | Lo que se devuelve; sera el total de la siguiente vuelta. Fijate en que es + y no +=: el acumulador ya conserva el valor por si mismo. |
0 | El valor inicial, despues de la funcion. Se asigna a total en la primera vuelta. |
const carrito = [
{ nombre: 'Monitor', precio: 500 },
{ nombre: 'Tablet', precio: 100 }
];
console.log(carrito.reduce((total, p) => total + p.precio, 0)); // 600
console.log(carrito.reduce((total, p) => total + p.precio, 2000)); // 2600 (gastos previos)
12.5 filter: el que mas usaras
filter crea un arreglo nuevo con todos los elementos que cumplan la
condicion. Es la base de cualquier buscador con filtros.
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Audifonos', precio: 300 },
{ nombre: 'Teclado', precio: 400 },
{ nombre: 'Celular', precio: 700 }
];
// Todos los que cuestan mas de 400
const caros = carrito.filter(producto => producto.precio > 400);
console.log(caros);
// Todos los que cuestan menos de 600
const baratos = carrito.filter(producto => producto.precio < 600);
console.log(baratos);
El caso estrella: eliminar del carrito
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Audifonos', precio: 300 }
];
// "Traeme todos MENOS los audifonos"
const resultado = carrito.filter(producto => producto.nombre !== 'Audifonos');
console.log(resultado);
console.log('El carrito original sigue completo:', carrito.length);
✓ Por que se usa tanto
En la Unidad 8 eliminabas con splice, que
modifica el arreglo original y exige conocer la posicion. Con filter solo describes
que quieres conservar y obtienes un arreglo nuevo. Es la forma habitual de eliminar
elementos en aplicaciones modernas.
12.6 find: traer el elemento, no su posicion
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 700 }
];
const indice = carrito.findIndex(producto => producto.nombre === 'Tablet');
const objeto = carrito.find(producto => producto.nombre === 'Tablet');
console.log(indice); // 1 -> la POSICION
console.log(objeto); // { nombre... } -> el OBJETO completo
const carrito = [{ nombre: 'Tablet', precio: 100 }];
console.log(carrito.find(p => p.nombre === 'Monitor')); // undefined
console.log(carrito.findIndex(p => p.nombre === 'Monitor')); // -1
⚠ find tambien devuelve solo el primero
Si dos productos cumplen la condicion, find se queda con el primero. Para obtener
todos, usa filter.
12.7 every: que lo cumplan todos
some devuelve true si al menos uno cumple la condicion.
every exige que la cumplan todos.
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 700 }
];
// TODOS cuestan menos de 1000?
console.log(carrito.every(producto => producto.precio < 1000)); // true
// TODOS cuestan menos de 500?
console.log(carrito.every(producto => producto.precio < 500)); // false
// ALGUNO cuesta menos de 500?
console.log(carrito.some(producto => producto.precio < 500)); // true
💡 La analogia que lo fija
every es el && de los arreglos (todas las condiciones) y
some es el || (basta una). Los operadores logicos de la Unidad 10,
aplicados a una coleccion entera.
12.8 Unir arreglos: concat y spread
const meses = ['Enero', 'Febrero', 'Marzo'];
const meses2 = ['Abril', 'Mayo', 'Junio'];
const meses3 = ['Julio', 'Agosto', 'Septiembre'];
const resultado = meses.concat(meses2, meses3);
console.log(resultado);
const meses = ['Enero', 'Febrero', 'Marzo'];
const meses2 = ['Abril', 'Mayo', 'Junio'];
const meses3 = ['Julio', 'Agosto', 'Septiembre'];
const resultado2 = [...meses, ...meses2, ...meses3];
console.log(resultado2);
// El orden determina el resultado
const alReves = [...meses3, ...meses];
console.log(alReves);
💡 Caso real donde el orden importa
En un gestor de tareas tipo Trello o Asana, las tareas nuevas suelen aparecer arriba. Ese
comportamiento se consigue escribiendo [nuevaTarea, ...tareas], poniendo lo nuevo
delante de la copia del arreglo.
12.9 Mas sobre el spread operator
const meses = ['Enero', 'Febrero', 'Marzo'];
const meses2 = [...meses, 'Abril'];
console.log(meses); // ['Enero', 'Febrero', 'Marzo'] <-- intacto
console.log(meses2); // con Abril al final
const meses = ['Enero', 'Febrero', 'Marzo'];
meses.push('Abril');
console.log(meses); // el original ha cambiado
💡 Programacion funcional
Uno de los principios de la programacion funcional es no modificar los datos originales, sino crear versiones nuevas. El spread operator es la herramienta principal para lograrlo, y por eso es tan habitual en JavaScript moderno y en React.
Dos errores tipicos
const meses = ['Enero', 'Febrero'];
// MAL: los tres puntos descomponen el texto letra por letra
console.log([...meses, ...'Marzo']);
// BIEN: un string se anade tal cual, sin los tres puntos
console.log([...meses, 'Marzo']);
const carrito = [{ nombre: 'Monitor', precio: 400 }];
const producto = { nombre: 'Disco duro', precio: 300 };
// BIEN: el objeto se anade entero, sin los tres puntos
const carrito2 = [...carrito, producto];
console.log(carrito2);
// Si pusieras [...carrito, ...producto] obtendrias:
// TypeError: producto is not iterable
⚠ La regla
Los tres puntos van delante de lo que quieres descomponer (otro arreglo). Lo que quieres anadir como un unico elemento va sin ellos.
12.10 Chuleta: ¿cual necesito?
| Quiero saber / hacer... | Metodo | Devuelve |
|---|---|---|
| ¿Existe este valor? (arreglo plano) | includes() | true / false |
| ¿Existe? (tambien con objetos) | some() | true / false |
| ¿Lo cumplen todos? | every() | true / false |
| ¿En que posicion esta? | findIndex() | Numero, o -1 |
| Traeme el elemento | find() | El elemento, o undefined |
| Traeme todos los que cumplan | filter() | Arreglo nuevo |
| Transformar cada elemento | map() | Arreglo nuevo |
| Hacer algo con cada elemento | forEach() | undefined |
| Reducirlo todo a un valor | reduce() | Un unico valor |
| Unir arreglos | concat() o [...a, ...b] | Arreglo nuevo |
💡 Los dos que mas usaras
filter y reduce. El primero para
seleccionar, el segundo para totalizar. Aparecen en practicamente todos los proyectos del curso.
12.11 Ejercicios practicos
Resumen del carrito
Con el carrito de la seccion 12.1, calcula y muestra: cuantos productos hay, el total a pagar, si hay algun producto que cueste mas de 600, y si todos cuestan mas de 50.
Ver solucion
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Audifonos', precio: 300 },
{ nombre: 'Teclado', precio: 400 },
{ nombre: 'Celular', precio: 700 }
];
console.log('Productos:', carrito.length);
console.log('Total:', carrito.reduce((total, p) => total + p.precio, 0));
console.log('Alguno > 600?', carrito.some(p => p.precio > 600));
console.log('Todos > 50?', carrito.every(p => p.precio > 50));
Eliminar del carrito
La persona pulsa el boton de eliminar sobre el Teclado. Quitalo del carrito con
filter y recalcula el nuevo total.
Ver solucion
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Teclado', precio: 400 }
];
const totalAntes = carrito.reduce((total, p) => total + p.precio, 0);
console.log('Total antes:', totalAntes);
const nuevoCarrito = carrito.filter(p => p.nombre !== 'Teclado');
const totalDespues = nuevoCarrito.reduce((total, p) => total + p.precio, 0);
console.log('Productos restantes:', nuevoCarrito.length);
console.log('Total despues:', totalDespues);
Un buscador con filtros
Con un arreglo de coches (marca, color, precio, puertas), escribe un buscador que devuelva los que sean de una marca concreta y cuesten menos de un maximo. Es la base del proyecto de buscador de autos del curso.
Ver solucion
const autos = [
{ marca: 'Ford', color: 'negro', precio: 65000, puertas: 4 },
{ marca: 'BMW', color: 'blanco', precio: 90000, puertas: 2 },
{ marca: 'Ford', color: 'rojo', precio: 72000, puertas: 4 },
{ marca: 'BMW', color: 'negro', precio: 120000, puertas: 4 },
{ marca: 'Audi', color: 'blanco', precio: 85000, puertas: 2 }
];
function buscar(marca, precioMaximo) {
const resultado = autos
.filter(auto => auto.marca === marca)
.filter(auto => auto.precio <= precioMaximo);
if (resultado.length === 0) {
console.log('No hay resultados');
return;
}
console.log(`${resultado.length} resultado(s):`);
resultado.forEach(auto => console.log(` ${auto.marca} ${auto.color} - ${auto.precio}`));
}
buscar('Ford', 80000);
buscar('BMW', 100000);
buscar('Audi', 50000);
💡 Fijate en el encadenamiento
Como filter devuelve un arreglo, puedes aplicarle otro filter
directamente. Asi se anaden tantos criterios de busqueda como quieras sin complicar el codigo.
Ticket completo en una cadena
A partir del carrito, genera un ticket que muestre cada linea como
"Producto x1 .... 500" y al final el total con el 16% de impuesto,
combinando map, forEach y reduce.
Ver solucion
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 700 }
];
// 1. map transforma cada objeto en una linea de texto
const lineas = carrito.map(p => `${p.nombre} x1 .... ${p.precio}`);
// 2. forEach las imprime
console.log('--- TICKET ---');
lineas.forEach(linea => console.log(linea));
// 3. reduce calcula el subtotal
const subtotal = carrito.reduce((total, p) => total + p.precio, 0);
console.log('--------------');
console.log(`Subtotal: ${subtotal}`);
console.log(`IVA 16%: ${(subtotal * 0.16).toFixed(2)}`);
console.log(`TOTAL: ${(subtotal * 1.16).toFixed(2)}`);
Cada metodo hace una sola cosa: map transforma, forEach muestra y
reduce acumula. Elegir el metodo adecuado para cada tarea es justo lo que separa
el codigo legible del codigo enredado.
12.12 Resumen de lo aprendido
- Los array methods sustituyen a los bucles manuales y reducen el codigo a una linea.
- Todos reciben una arrow function a la que se le pasa cada elemento automaticamente.
includes()comprueba si existe un valor (solo arreglos planos);some()hace lo mismo y ademas sirve con objetos.every()exige que todos cumplan la condicion;some()se conforma con uno.findIndex()devuelve la posicion (o-1);find()devuelve el elemento (oundefined). Ambos solo el primero.filter()devuelve un arreglo nuevo con todos los que cumplen. Es la forma moderna de eliminar elementos.reduce()acumula todo en un valor. Su primer parametro es el acumulador y el segundo el elemento; el valor inicial va despues de la funcion.- Unir arreglos:
concat()o[...a, ...b]. El orden determina el resultado. - El spread operator no modifica el original, a diferencia de
push. Es la base de la programacion funcional.
12.13 Verificacion de cierre
¿Cual de estos no funciona con un arreglo de objetos?
some()filter()findIndex()includes()
En carrito.reduce((total, producto) => ...), ¿que es total?
- El numero de elementos del arreglo
- El acumulador: el valor arrastrado desde la vuelta anterior
- El elemento actual del arreglo
- El indice de la vuelta actual
Quieres todos los productos que cuesten mas de 400. ¿Que metodo usas?
filter()find()findIndex()some()
🏁 Unidad completada