Saltar al contenido
Curso de JavaScriptModerno · Interactivo

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.

📚 10 lecciones originales ⏱ Lectura ~35 min ↩ Requiere: Unidad 7

🎯 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

ObjetoArreglo
Sirve paraUn elemento con varias propiedadesVarios elementos relacionados
SintaxisLlaves { }Corchetes [ ]
EstructuraPares llave: valorSolo valores, separados por comas
Se accede porEl nombre de la llaveLa posicion (indice)
Las dos formas de crear un arreglo
// 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:

Todos los tipos de dato, incluso otros arreglos
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.

Acceder por posicion
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

Doble indice
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

La propiedad length
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

Recorrer con for
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

ParteCodigoQue significa
1. Inicializadorlet i = 0Empieza a contar desde la primera posicion del arreglo.
2. Condicioni < meses.lengthRepite mientras el contador sea menor que el tamano. Asi se adapta solo.
3. Incrementoi++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

Asignar directamente a una posicion
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.

push: anade al final
const meses = ['Enero', 'Febrero', 'Marzo'];

meses.push('Abril');
meses.push('Mayo');

console.log(meses);

Un carrito de compras real

Arreglo de objetos: el patron mas comun
// 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.
Anadir sin modificar el original
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

Delante o detras de la copia
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...ImperativoDeclarativo
Anadir al finalarr.push(x)[...arr, x]
Anadir al inicioarr.unshift(x)[x, ...arr]

8.7 Eliminar elementos: pop, shift y splice

Eliminar de los extremos
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.

splice(desde, cuantos)
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);
Eliminar varios de golpe
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.

Extraer por 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.

Las comas vacias saltan posiciones
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

El rest operator en destructuring
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

Con for, sobre un arreglo de objetos
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

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 producto le 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

map devuelve un arreglo nuevo; forEach no
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

Ejercicio 1

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
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);
Ejercicio 2

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
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);
Reto 1

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
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.

Reto 2

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
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.
  • .length dice cuantos elementos hay. Es lo que permite recorrer arreglos de tamano variable.
  • El for loop 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. ...resto recoge lo que quede.
  • forEach recorre; map recorre y devuelve un arreglo nuevo.
  • const no 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
  • -1
  • 4
  • 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