Unidad 8 · Lecciones 048-057
Arrays o Arreglos
Si un objeto describe una cosa, un arreglo guarda muchas. El carrito de compras de Amazon, la lista de tus amigos en una red social, los meses del ano: todo eso son arreglos. Y casi siempre son arreglos de objetos, que es donde se junta todo lo que has aprendido hasta ahora.
🎯 Objetivo de aprendizaje
Al terminar sabras crear arreglos, acceder a sus elementos por indice, recorrerlos completos,
anadir y eliminar elementos tanto de forma imperativa como declarativa, aplicar destructuring
y usar forEach y map.
8.1 Crear un arreglo
💡 Objeto frente a arreglo
| Objeto | Arreglo | |
|---|---|---|
| Sirve para | Un elemento con varias propiedades | Varios elementos relacionados |
| Sintaxis | Llaves { } | Corchetes [ ] |
| Estructura | Pares llave: valor | Solo valores, separados por comas |
| Se accede por | El nombre de la llave | La posicion (indice) |
// 1. Con corchetes (la habitual)
const numeros = [10, 20, 30];
console.log(numeros);
// 2. Con el constructor (menos comun)
const meses = new Array('Enero', 'Febrero', 'Marzo');
console.log(meses);
Un arreglo puede contener de todo
Aunque lo recomendable es agrupar elementos relacionados, el lenguaje no te obliga:
const deTodo = [
'Hola', // string
10, // numero
true, // boolean
null, // null
{ nombre: 'Juan', trabajo: 'Programador' },// objeto
[1, 2, 3] // otro arreglo
];
console.log(deTodo);
JavaScript no protesta. Pero en un proyecto real, un arreglo asi seria dificilisimo de manejar.
8.2 Los indices: acceder a un elemento
⚠ Los arreglos empiezan en 0
El primer elemento ocupa la posicion 0, no la 1. Es la fuente de errores mas comun al empezar con arreglos.
const numeros = [10, 20, 30, 40, 50];
console.table(numeros); // muestra indice y valor en forma de tabla
console.log(numeros[0]); // 10 <-- el PRIMERO es el indice 0
console.log(numeros[2]); // 30
console.log(numeros[4]); // 50 <-- el ultimo de cinco es el indice 4
console.log(numeros[20]); // undefined: esa posicion no existe
Arreglos dentro de arreglos
const numeros = [10, 20, 30, 40, 50, [1, 2, 3]];
console.log(numeros[5]); // [1, 2, 3] el arreglo interior
console.log(numeros[5][1]); // 2 el segundo elemento de ese arreglo
8.3 Recorrer un arreglo completo
Este es el problema central de la unidad. Si alguien tiene 3 productos en el carrito puedes
escribir tres console.log. ¿Y si tiene 100? ¿Y si manana anade uno mas?
Necesitas codigo que se adapte al tamano del arreglo.
Primero: cuanto mide el arreglo
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];
console.log(meses.length); // 6
💡 Detalle que importa
length cuenta desde 1 (hay 6 meses), pero los indices
empiezan en 0 (van del 0 al 5). Por eso el ultimo indice siempre es
length - 1.
El for loop
const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio'];
for (let i = 0; i < meses.length; i++) {
console.log(meses[i]);
}
Las tres partes del parentesis
| Parte | Codigo | Que significa |
|---|---|---|
| 1. Inicializador | let i = 0 | Empieza a contar desde la primera posicion del arreglo. |
| 2. Condicion | i < meses.length | Repite mientras el contador sea menor que el tamano. Asi se adapta solo. |
| 3. Incremento | i++ | Avanza de uno en uno a la siguiente posicion. |
⚠ Por que let y no const
Porque i cambia de valor en cada vuelta. Una constante no se puede reasignar,
asi que el bucle fallaria.
✓ La clave del length
Si alguien anade un mes, el bucle da 7 vueltas. Si elimina dos, da 4. Nunca tienes que tocar el codigo: se ajusta solo. Eso es exactamente lo que hace el carrito de Amazon.
8.4 Modificar y anadir por indice
const meses = ['Enero', 'Febrero', 'Marzo'];
// Sobrescribir una posicion existente
meses[0] = 'Nuevo mes';
console.log(meses);
// Anadir en una posicion libre
meses[3] = 'Ultimo mes';
console.log(meses);
🎓 Pregunta de entrevista
¿Se puede modificar el contenido de una variable declarada con const?
Si, cuando es un objeto o un arreglo. Igual que con los objetos (Unidad 7), const
solo impide reasignar la variable completa. Nota ademas que los arreglos no tienen
equivalentes de freeze o seal tan habituales como los objetos.
+ Curiosidad
Si asignas a una posicion muy lejana (meses[10] = 'x' en un arreglo de 4), otros
lenguajes rellenan los huecos con valores vacios. JavaScript simplemente salta de la posicion 3
a la 10 y deja el resto sin definir. Es tecnicamente valido, pero mejor no depender de ello.
8.5 Anadir sin conocer la posicion: push y unshift
Escribir meses[3] = 'Abril' funciona, pero te obliga a saber cuantos elementos hay.
Estos dos metodos lo resuelven solos.
const meses = ['Enero', 'Febrero', 'Marzo'];
meses.push('Abril');
meses.push('Mayo');
console.log(meses);
Un carrito de compras real
// Cuando entras a una tienda, el carrito esta vacio
const carrito = [];
const producto = { nombre: 'Monitor de 32 pulgadas', precio: 400 };
const producto2 = { nombre: 'Celular', precio: 800 };
const producto3 = { nombre: 'Teclado', precio: 50 };
// La persona pulsa "Agregar al carrito"
carrito.push(producto);
carrito.push(producto2);
// Este lo queremos al PRINCIPIO: unshift
carrito.unshift(producto3);
console.table(carrito);
- .push(elemento)
- Anade al final del arreglo. Busca la ultima posicion libre por ti.
- .unshift(elemento)
- Anade al principio, empujando todo lo demas una posicion.
8.6 Imperativo frente a declarativo: el spread operator
ECMAScript 6 introdujo formas alternativas de hacer lo mismo. La diferencia no es cosmetica: cambia si el arreglo original se modifica o no.
- Forma imperativa
push,unshift,splice. Muy claras de leer, pero modifican el arreglo original directamente.
- Forma declarativa
- El spread operator. Menos evidente al principio, pero crea un arreglo nuevo y deja el original intacto.
const carrito = [];
const producto = { nombre: 'Monitor de 32 pulgadas', precio: 400 };
const producto2 = { nombre: 'Celular', precio: 800 };
// Los tres puntos toman una copia del contenido de carrito
let resultado = [...carrito, producto];
console.log('Tras el primero:', resultado);
resultado = [...resultado, producto2];
console.log('Tras el segundo:', resultado);
console.log('El carrito original sigue vacio:', carrito);
El orden importa
const carrito = [{ nombre: 'Monitor' }, { nombre: 'Celular' }];
const teclado = { nombre: 'Teclado' };
const alFinal = [...carrito, teclado]; // el teclado va al final
const alInicio = [teclado, ...carrito]; // el teclado va al principio
console.log('Al final:', alFinal);
console.log('Al inicio:', alInicio);
💡 Equivalencias
| Quiero... | Imperativo | Declarativo |
|---|---|---|
| Anadir al final | arr.push(x) | [...arr, x] |
| Anadir al inicio | arr.unshift(x) | [x, ...arr] |
8.7 Eliminar elementos: pop, shift y splice
const carrito = [
{ nombre: 'Teclado', precio: 50 },
{ nombre: 'Monitor', precio: 400 },
{ nombre: 'Celular', precio: 800 }
];
// pop: elimina el ULTIMO
carrito.pop();
console.log('Tras pop:', carrito);
// shift: elimina el PRIMERO
carrito.shift();
console.log('Tras shift:', carrito);
💡 Compara con los objetos
En un objeto eliminabas con delete objeto.propiedad. En un arreglo hay metodos
especificos porque lo que importa es la posicion, no un nombre.
splice: eliminar por el medio
En una tienda real no eliminas solo el primero o el ultimo: eliminas el que la persona ha
pulsado. Para eso esta splice, que recibe dos argumentos.
const carrito = [
{ nombre: 'Teclado', precio: 50 },
{ nombre: 'Celular', precio: 800 },
{ nombre: 'Monitor', precio: 400 },
{ nombre: 'Audifonos', precio: 120 }
];
// Eliminar 1 elemento a partir de la posicion 1 (el Celular)
carrito.splice(1, 1);
console.table(carrito);
const carrito = [
{ nombre: 'Teclado' },
{ nombre: 'Celular' },
{ nombre: 'Monitor' },
{ nombre: 'Audifonos' }
];
// Desde la posicion 1, eliminar 2 elementos
carrito.splice(1, 2);
console.table(carrito);
+ splice puede imitar a los otros dos
arr.splice(0, 1) hace lo mismo que arr.shift(), y
arr.splice(arr.length - 1, 1) lo mismo que arr.pop().
En un carrito real casi siempre eliminaras un elemento.
8.8 Destructuring de arreglos
Igual que en los objetos, puedes extraer valores y crear variables en un paso. La diferencia: se usan corchetes y tu eliges los nombres, porque lo que manda es la posicion.
const numeros = [10, 20, 30, 40, 50];
const [primero, segundo, tercero] = numeros;
console.log(primero); // 10
console.log(segundo); // 20
console.log(tercero); // 30
Saltar posiciones que no necesitas
Si solo te interesa el tercero, no crees dos variables inutiles: deja el hueco vacio con una coma.
const numeros = [10, 20, 30, 40, 50];
// Saltar las dos primeras posiciones
const [, , tercero] = numeros;
console.log(tercero); // 30
// Solo la quinta
const [, , , , quinto] = numeros;
console.log(quinto); // 50
⚠ Elimina las variables que no uses
Crear variables que nunca lees anade peso innecesario a tu programa y confunde a quien lea el codigo despues.
Recoger el resto en un arreglo
const numeros = [10, 20, 30, 40, 50];
const [primero, segundo, ...tercero] = numeros;
console.log(primero); // 10
console.log(segundo); // 20
console.log(tercero); // [30, 40, 50] <-- todo lo demas, en un arreglo
Esta sintaxis es omnipresente en React y en el desarrollo frontend moderno. Si alguna vez la has visto sin entenderla, ahora ya sabes que hace: separa los primeros elementos y mete el resto en un arreglo nuevo.
8.9 forEach y map
+ Nota sobre el orden
Estos dos reciben una funcion como argumento, y las funciones son el tema de la Unidad 9. El curso original tambien los introduce aqui, asi que se explican al nivel justo para usarlos; volveran con mas profundidad en las Unidades 9, 11 y 12.
El punto de partida: el for tradicional
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 800 }
];
for (let i = 0; i < carrito.length; i++) {
console.log(`${carrito[i].nombre} - precio: ${carrito[i].precio}`);
}
Funciona, pero fijate en cuantas veces tienes que escribir carrito[i].
Lo mismo con forEach
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 800 }
];
carrito.forEach(function(producto) {
console.log(`${producto.nombre} - precio: ${producto.precio}`);
});
Que ha cambiado
carrito.forEach(...)— punto seguido del nombre: es un metodo del arreglo.- Recorre el arreglo una vez por elemento, sin que tengas que contar nada.
- A
productole pones el nombre que quieras: es cada elemento de la vuelta actual. Un nombre descriptivo hace el codigo mucho mas legible. - Ya no hace falta
carrito[i]: dentro tienes el objeto directamente.
💡 Funcion frente a metodo
Cuando ves algo() suelto, es una funcion. Cuando ves
variable.algo(), con un punto delante, es un metodo: una funcion que
pertenece a ese dato.
La diferencia entre forEach y map
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 }
];
// map: lo que retornes se guarda en un arreglo nuevo
const nuevoArreglo = carrito.map(function(producto) {
return `${producto.nombre} - precio: ${producto.precio}`;
});
// forEach: no devuelve nada
const nuevoArreglo2 = carrito.forEach(function(producto) {
return `${producto.nombre} - precio: ${producto.precio}`;
});
console.log(nuevoArreglo); // el arreglo con los textos
console.log(nuevoArreglo2); // undefined
🎓 Pregunta de entrevista
¿Cual es la diferencia entre forEach y map?
En sintaxis son identicos y ambos recorren el arreglo completo. La diferencia es que
map crea y devuelve un arreglo nuevo con lo que retornes en cada
vuelta, mientras que forEach devuelve undefined.
Usa forEach para hacer algo con cada elemento y map para
transformar el arreglo.
8.10 Ejercicios practicos
Carrito completo
Partiendo de un carrito vacio: anade tres productos (uno de ellos al principio),
muestralo con console.table, elimina el que este en la posicion 1
y vuelve a mostrarlo.
Ver solucion
const carrito = [];
const monitor = { nombre: 'Monitor', precio: 400 };
const celular = { nombre: 'Celular', precio: 800 };
const teclado = { nombre: 'Teclado', precio: 50 };
carrito.push(monitor);
carrito.push(celular);
carrito.unshift(teclado); // este al principio
console.log('Carrito inicial:');
console.table(carrito);
carrito.splice(1, 1); // eliminar el de la posicion 1
console.log('Tras eliminar la posicion 1:');
console.table(carrito);
La version que no destruye
Repite el ejercicio anterior pero sin modificar el arreglo original: usa el spread operator para construir el carrito.
Ver solucion
const carrito = [];
const monitor = { nombre: 'Monitor', precio: 400 };
const celular = { nombre: 'Celular', precio: 800 };
const teclado = { nombre: 'Teclado', precio: 50 };
let resultado = [...carrito, monitor];
resultado = [...resultado, celular];
resultado = [teclado, ...resultado]; // este al principio
console.table(resultado);
console.log('El carrito original sigue vacio:', carrito);
Listar el carrito con las tres tecnicas
Dado un carrito de cuatro productos, muestra el nombre y el precio de cada uno
tres veces: con un for, con forEach y con
map. Con map, guarda el resultado en una variable y muestrala.
Ver solucion
const carrito = [
{ nombre: 'Monitor 27 pulgadas', precio: 500 },
{ nombre: 'Tablet', precio: 100 },
{ nombre: 'Celular', precio: 800 },
{ nombre: 'Teclado', precio: 50 }
];
console.log('--- con for ---');
for (let i = 0; i < carrito.length; i++) {
console.log(`${carrito[i].nombre}: ${carrito[i].precio}`);
}
console.log('--- con forEach ---');
carrito.forEach(function(producto) {
console.log(`${producto.nombre}: ${producto.precio}`);
});
console.log('--- con map ---');
const resumen = carrito.map(function(producto) {
return `${producto.nombre}: ${producto.precio}`;
});
console.log(resumen);
Los tres producen la misma informacion. La diferencia esta en la legibilidad y en que
map te deja un arreglo reutilizable.
Separar el primero del resto
Una API te devuelve un arreglo de noticias. La primera debe mostrarse destacada y el resto en una lista. Usa destructuring con rest operator para separarlas.
Ver solucion
const noticias = [
'JavaScript cumple 30 anos',
'Nuevo framework de moda',
'Como aprobar una entrevista tecnica',
'Las 10 extensiones imprescindibles'
];
const [destacada, ...resto] = noticias;
console.log('DESTACADA:', destacada);
console.log('Resto (' + resto.length + ' noticias):');
resto.forEach(function(noticia) {
console.log('- ' + noticia);
});
8.11 Resumen de lo aprendido
- Un arreglo agrupa varios elementos. Se crea con corchetes
[ ]y sus valores se separan con comas. - Los indices empiezan en 0. El ultimo elemento esta en
length - 1. .lengthdice cuantos elementos hay. Es lo que permite recorrer arreglos de tamano variable.- El
forloop tiene tres partes: inicializador, condicion e incremento. - Anadir (imperativo):
push()al final,unshift()al principio. Modifican el original. - Anadir (declarativo):
[...arr, x]o[x, ...arr]. Crean un arreglo nuevo. - Eliminar:
pop()el ultimo,shift()el primero,splice(desde, cuantos)por el medio. - Destructuring: con corchetes; tu eliges los nombres y las comas vacias saltan posiciones.
...restorecoge lo que quede. forEachrecorre;maprecorre y devuelve un arreglo nuevo.constno impide modificar un arreglo, solo reasignarlo.
8.12 Verificacion de cierre
En const n = [10, 20, 30, 40, 50], ¿que indice tiene el 50?
5-14- Depende del navegador
¿Que hace carrito.splice(1, 2)?
- Elimina los elementos de las posiciones 1 y 2
- Elimina 2 elementos empezando en la posicion 1
- Anade 2 elementos en la posicion 1
- Divide el arreglo en dos desde la posicion 1
¿Cual de estas operaciones no modifica el arreglo original?
carrito.push(producto)carrito.unshift(producto)carrito.splice(0, 1)[...carrito, producto]
🏁 Unidad completada