Lección 5 de 8. Casi todos los datos de un programa de JavaScript viven en arrays y objetos. Esta lección recorre los métodos que más se usan, la desestructuración, y lo que más errores causa: que asignar un objeto no lo copia.
Arrays: lo básico
Un array es una lista ordenada de valores de cualquier tipo. Crece y encoge solo, y se accede a cada elemento por su posición, empezando en 0:
const cesta = ["pan", "leche"];
cesta.push("café"); // añade al final
cesta.unshift("miel"); // añade al principio
console.log(cesta, cesta.length);
console.log(cesta[0], cesta.at(-1)); // el primero y el último
console.log(cesta.includes("leche"), cesta.indexOf("té"));
const ultimo = cesta.pop(); // quita y devuelve el último
console.log(ultimo, cesta);salida[ 'miel', 'pan', 'leche', 'café' ] 4 miel café true -1 café [ 'miel', 'pan', 'leche' ]
at(-1) cuenta desde el final, cosa que cesta[-1] no hace (daría undefined). indexOf devuelve -1 cuando no encuentra el elemento, y includes, directamente un booleano, que es lo que casi siempre quieres preguntar.
map, filter y reduce
Son los tres métodos que más vas a usar. Ninguno modifica el array original: devuelven uno nuevo (o un valor, en el caso de reduce). Con esta lista de productos:
const productos = [
{ nombre: "pan", precio: 1.2, stock: 10 },
{ nombre: "leche", precio: 0.95, stock: 0 },
{ nombre: "café", precio: 7.5, stock: 3 },
{ nombre: "miel", precio: 4.9, stock: 1 },
];const conStock = productos.filter((p) => p.stock > 0);
const valores = conStock.map((p) => p.precio * p.stock);
const total = valores.reduce((suma, v) => suma + v, 0);
console.log(conStock.map((p) => p.nombre));
console.log(valores);
console.log("valor del almacén:", total.toFixed(2));salida[ 'pan', 'café', 'miel' ] [ 12, 22.5, 4.9 ] valor del almacén: 39.40
filter se queda con los elementos que cumplen la condición, map transforma cada uno y reduce los combina en un solo valor. Esquema: decodigo.com.reduce es el que más cuesta leer. Recibe una función con dos parámetros, el acumulado hasta ahora y el elemento actual, y el valor inicial del acumulado (el 0 del final). En cada vuelta, lo que devuelve la función pasa a ser el nuevo acumulado. No te saltes ese valor inicial: sin él, reduce sobre un array vacío lanza un error.
Como cada método devuelve un array, se pueden encadenar en una sola expresión, una línea por paso:
const total = productos .filter((p) => p.stock > 0) .map((p) => p.precio * p.stock) .reduce((suma, v) => suma + v, 0); console.log(total.toFixed(2));
salida39.40
Buscar: find, findIndex, some y every
console.log(productos.find((p) => p.precio > 5)); console.log(productos.findIndex((p) => p.nombre === "miel")); console.log(productos.some((p) => p.stock === 0)); // ¿alguno agotado? console.log(productos.every((p) => p.precio < 10)); // ¿todos por debajo de 10? console.log(productos.find((p) => p.nombre === "kiwi"));
salida{ nombre: 'café', precio: 7.5, stock: 3 }
3
true
true
undefinedLa última línea es la que da problemas: si find no encuentra nada, devuelve undefined, y el error llega en la línea siguiente, al usar el resultado:
const kiwi = productos.find((p) => p.nombre === "kiwi"); console.log(kiwi.precio);
salidaTypeError: Cannot read properties of undefined (reading 'precio')
Comprueba el resultado antes de usarlo, o usa kiwi?.precio si no encontrarlo es normal (el encadenamiento opcional de la lección 3).
Ordenar: sort y toSorted
const nombres = ["Luis", "ana", "Álvaro", "Bea"]; const copia = nombres.toSorted((a, b) => a.localeCompare(b, "es")); console.log(copia); console.log(nombres); // intacto nombres.sort((a, b) => (a < b ? -1 : 1)); console.log(nombres); // sort sí lo modifica const porPrecio = productos.toSorted((a, b) => a.precio - b.precio); console.log(porPrecio.map((p) => p.nombre));
salida[ 'Álvaro', 'ana', 'Bea', 'Luis' ] [ 'Luis', 'ana', 'Álvaro', 'Bea' ] [ 'Bea', 'Luis', 'ana', 'Álvaro' ] [ 'leche', 'pan', 'miel', 'café' ]
Tres cosas que conviene saber. sort modifica el array que ordena; toSorted, más reciente, devuelve uno nuevo y deja el original como estaba. La función que reciben compara dos elementos y devuelve un número negativo si el primero va antes, positivo si va después: por eso a.precio - b.precio ordena de menor a mayor. Y para texto, localeCompare con el idioma pone la «Á» con la «A» y no distingue mayúsculas, mientras que comparar con < ordena por el código de cada carácter y manda «ana» y «Álvaro» al final. Lo de llamar a sort() sin función, que ordena los números como si fueran texto, está en las rarezas de JavaScript.
Objetos
Un objeto es una colección de pares clave y valor. Las claves son cadenas y los valores, cualquier cosa, también funciones:
const nombre = "Ana";
const campo = "ciudad";
const usuario = {
nombre, // igual que nombre: nombre
edad: 34,
[campo]: "Quito", // clave calculada
saludar() {
return `Hola, soy ${this.nombre}`;
},
};
console.log(usuario.saludar());
console.log(usuario["edad"], usuario.ciudad);
console.log(Object.keys(usuario));
console.log("edad" in usuario, Object.hasOwn(usuario, "telefono"));
delete usuario.edad;
console.log(Object.entries(usuario).filter(([, v]) => typeof v !== "function"));salidaHola, soy Ana 34 Quito [ 'nombre', 'edad', 'ciudad', 'saludar' ] true false [ [ 'nombre', 'Ana' ], [ 'ciudad', 'Quito' ] ]
El punto y los corchetes son equivalentes; los corchetes hacen falta cuando la clave está en una variable o tiene caracteres raros. Object.keys, Object.values y Object.entries convierten el objeto en arrays, y así se le pueden aplicar todos los métodos de arriba.
Desestructurar y propagar
La desestructuración saca valores de un array o de un objeto y los guarda en variables, en una línea:
const [primero, segundo, ...resto] = [10, 20, 30, 40];
console.log(primero, segundo, resto);
const usuario = { nombre: "Ana", edad: 34 };
const { nombre, edad: años, pais = "desconocido" } = usuario;
console.log(nombre, años, pais);
// también en los parámetros de una función
function ficha({ nombre, edad }) {
return `${nombre} (${edad})`;
}
console.log(ficha(usuario));
// e intercambiar dos variables sin una auxiliar
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b);salida10 20 [ 30, 40 ] Ana 34 desconocido Ana (34) 2 1
En los objetos se pueden renombrar (edad: años) y dar un valor por omisión (pais = "desconocido"). La versión en parámetros es muy común: deja claro qué propiedades usa la función y permite llamarla con un objeto de opciones.
La propagación con ..., que en la lección 4 repartía un array en argumentos, también copia los elementos de un array o las propiedades de un objeto dentro de otro:
const base = { tema: "claro", idioma: "es", avisos: true };
const delUsuario = { tema: "oscuro" };
const config = { ...base, ...delUsuario };
console.log(config);
const juntos = [...[1, 2], 3, ...[4, 5]];
console.log(juntos);salida{ tema: 'oscuro', idioma: 'es', avisos: true }
[ 1, 2, 3, 4, 5 ]Si una clave se repite, gana la última: así se combinan unos valores por omisión con los que elige el usuario.
Referencias: la copia que no copia
Este es el concepto más importante de la lección. Una variable no guarda el objeto: guarda una referencia a él. Asignarla a otra variable no copia nada; las dos apuntan al mismo objeto.
const a = { nombre: "Ana", dir: { ciudad: "Quito" } };
const asignado = a;
const superficial = { ...a };
const profunda = structuredClone(a);
a.nombre = "Ana María";
a.dir.ciudad = "Lima";
console.log("asignado: ", asignado.nombre, asignado.dir.ciudad);
console.log("superficial:", superficial.nombre, superficial.dir.ciudad);
console.log("profunda: ", profunda.nombre, profunda.dir.ciudad);
console.log({} === {}, a === asignado);salidaasignado: Ana María Lima superficial: Ana Lima profunda: Ana Quito false true
... duplica solo el primer nivel: el objeto dir lo siguen compartiendo. structuredClone duplica todos los niveles. Esquema: decodigo.com.Por eso la copia superficial ve el cambio de ciudad pero no el de nombre: copió nombre, que es una cadena, pero de dir solo copió la referencia. Y por eso {} === {} es false: === entre objetos no compara su contenido, sino si son el mismo objeto.
structuredClone copia objetos, arrays, fechas, Map y Set, pero no funciones ni instancias de clases con sus métodos:
structuredClone({ nombre: "Ana", saludar() {} });salidaDOMException [DataCloneError]: saludar() {} could not be cloned.const no hace el objeto inmutable. Impide reasignar la variable, pero el objeto al que apunta se puede modificar sin problemas: por eso a.nombre = "Ana María" funcionó arriba. Lo que da error es esto:const lista = [1, 2]; lista.push(3); // bien: modifica el array lista = [4, 5]; // error: reasigna la variable
salidaTypeError: Assignment to constant variable.
Map y Set
Además de objetos y arrays, JavaScript tiene dos colecciones más especializadas. Set guarda valores sin repetir; Map, pares clave y valor en los que la clave puede ser de cualquier tipo:
const etiquetas = ["js", "web", "js", "node", "web"];
const unicas = new Set(etiquetas);
console.log(unicas, unicas.size, unicas.has("node"));
console.log([...unicas]); // de vuelta a array
const visitas = new Map();
const ana = { nombre: "Ana" };
visitas.set(ana, 3); // un objeto como clave
visitas.set("anónimo", 12);
console.log(visitas.get(ana), visitas.size);
for (const [quien, n] of visitas) {
console.log(quien.nombre ?? quien, n);
}salidaSet(3) { 'js', 'web', 'node' } 3 true
[ 'js', 'web', 'node' ]
3 2
Ana 3
anónimo 12| Necesitas | Usa |
|---|---|
| Una lista ordenada, con posiciones | array |
| Un registro con campos fijos (nombre, edad…) | objeto |
| Quitar duplicados o preguntar «¿está?» muchas veces | Set |
| Un diccionario que crece, con claves que no son texto o que se recorre en orden de inserción | Map |
JSON: pasar objetos a texto y volver
JSON es el formato de texto con el que se intercambian datos en la web, y su sintaxis viene de los objetos de JavaScript. JSON.stringify convierte un valor en texto y JSON.parse hace lo contrario:
const pedido = {
id: 7,
cliente: "Ana",
fecha: new Date(Date.UTC(2026, 9, 19)),
notas: undefined,
extras: new Map([["envio", "rápido"]]),
};
const texto = JSON.stringify(pedido);
console.log(texto);
const deVuelta = JSON.parse(texto);
console.log(typeof deVuelta.fecha, "notas" in deVuelta);
console.log(JSON.stringify({ a: 1, b: [1, 2] }, null, 2));salida{"id":7,"cliente":"Ana","fecha":"2026-10-19T00:00:00.000Z","extras":{}}
string false
{
"a": 1,
"b": [
1,
2
]
}No todo sobrevive al viaje: las propiedades con undefined desaparecen, la fecha vuelve como texto y no como fecha, y un Map se queda en un objeto vacío. El tercer argumento de stringify es la sangría, para que el resultado se pueda leer. Leer y escribir archivos JSON está en el ejemplo JSON en JavaScript.
Todo el código de esta lección se ejecutó con Node.js 24 en un contenedor limpio antes de publicarla; las salidas y los errores están copiados de esa ejecución.
