Lectura y copia de objetos en JavaScript

En esta página
Enterate del próximo post
Un mail cuando publico algo nuevo. Sin spam y te podés dar de baja cuando quieras.

Un mail cuando publico algo nuevo. Sin spam y te podés dar de baja cuando quieras.
El post sobre objetos mostró cómo crear uno, leer una propiedad puntual con punto o con corchetes, y agregar o cambiar valores de a una clave por vez. Faltó lo que sigue naturalmente después: leer todas las claves o todos los valores de una sola vez, copiar un objeto completo sin arrastrar la referencia original, y evitar que alguien lo cambie por accidente.
const producto = { nombre: "Mouse", precio: 4500, stock: 12 };
console.log(Object.keys(producto));
// [ 'nombre', 'precio', 'stock' ]Object.keys recibe un objeto y devuelve un array con el nombre de cada una de sus propiedades, en el mismo orden en que se declararon. A partir de ahí, ese array se puede tratar como cualquier otro: leer su length, acceder por índice, o pasarlo por map.
const producto = { nombre: "Mouse", precio: 4500 };
const claves = Object.keys(producto);
producto.stock = 12;
console.log(claves);
// [ 'nombre', 'precio' ]El array que devuelve Object.keys es una foto del momento en que se lo pidió, no una vista que se actualiza sola. Agregar stock al objeto después no cambia el array claves, que ya quedó armado con las dos propiedades que existían en ese instante.
const producto = { nombre: "Mouse", precio: 4500, stock: 12 };
console.log(Object.values(producto));
// [ 'Mouse', 4500, 12 ]
console.log(Object.entries(producto));
// [ [ 'nombre', 'Mouse' ], [ 'precio', 4500 ], [ 'stock', 12 ] ]Object.values hace lo mismo que Object.keys, pero con los valores en vez de los nombres. Object.entries devuelve las dos cosas juntas: un array donde cada elemento es, a su vez, un array de dos posiciones, la clave en el índice 0 y el valor en el índice 1.
Ese array de pares se puede recorrer con los mismos métodos que ya se usaron sobre cualquier array.
const precios = { teclado: 8000, mouse: 4500, monitor: 65000 };
const pares = Object.entries(precios);
const conDescuento = pares.map(function (par) {
return [par[0], par[1] * 0.9];
});
console.log(Object.fromEntries(conDescuento));
// { teclado: 7200, mouse: 4050, monitor: 58500 }pares.map transforma cada par en uno nuevo, con la misma clave (par[0]) y el valor con el descuento ya aplicado (par[1] * 0.9). El resultado sigue siendo un array de pares, no un objeto: Object.fromEntries hace el camino inverso a Object.entries, y arma un objeto nuevo a partir de ese array.
const original = { nombre: "Mouse", precio: 4500 };
const copia = { ...original };
copia.precio = 4000;
console.log(original.precio);
// 4500
console.log(copia.precio);
// 4000{ ...original } crea un objeto nuevo con las mismas propiedades que original, copiadas una por una. copia y original son, a partir de ahí, dos objetos independientes: cambiar precio en uno no toca al otro. Esto es distinto de asignar const copia = original, que no copia nada, solo hace que las dos variables apunten al mismo objeto (el mismo comportamiento de referencia que ya se vio antes con objetos y arrays).
const original = { nombre: "Mouse", precio: 4500 };
const copia = Object.assign({}, original);
copia.precio = 4000;
console.log(original.precio);
// 4500Object.assign({}, original) hace exactamente lo mismo que { ...original }: copia las propiedades de original sobre un objeto vacío recién creado. Es la forma que existía antes de que la sintaxis de spread llegara al lenguaje; hoy conviven las dos.
const original = { nombre: "Mouse", specs: { dpi: 800 } };
const copia = { ...original };
copia.specs.dpi = 1600;
console.log(original.specs.dpi);
// 1600Esta copia tiene un límite: solo copia un nivel de profundidad. specs es un objeto, y lo que { ...original } copia ahí no es un specs nuevo, es la misma referencia al specs original. Cambiar copia.specs.dpi cambia el único objeto specs que existe, así que original.specs.dpi también queda en 1600. Por eso a este tipo de copia se la llama superficial: duplica el objeto de arriba, pero no duplica los objetos que hay adentro.
const configuracion = { modo: "oscuro" };
Object.freeze(configuracion);
configuracion.modo = "claro";
console.log(configuracion.modo);
// oscuroObject.freeze marca un objeto para que ninguna de sus propiedades pueda cambiar de valor. El intento de asignación (configuracion.modo = "claro") no tira ningún error: simplemente no tiene efecto, y modo sigue siendo "oscuro".
const configuracion = Object.freeze({ modo: "oscuro" });
configuracion.idioma = "es";
console.log(configuracion);
// { modo: 'oscuro' }La misma protección aplica a una propiedad que todavía no existe: intentar agregar idioma tampoco tiene efecto. Object.freeze devuelve el propio objeto que recibe, así que se lo puede aplicar en la misma línea donde se lo crea, sin necesitar una variable intermedia.
Object.keys,Object.valuesyObject.entriesconvierten las propiedades de un objeto en un array, listo para recorrer con los mismos métodos que ya se usan sobre cualquier array;Object.fromEntrieshace el camino de vuelta. Copiar un objeto con{ ...original }oObject.assign({}, original)separa las dos variables, pero solo hasta el primer nivel: los objetos que haya adentro siguen siendo la misma referencia compartida.Object.freezebloquea cualquier cambio posterior, sin avisar ni fallar cuando alguien lo intenta igual.
El próximo post de la serie trata this, call, apply y bind: qué decide a qué apunta this dentro de una función, cómo fijarlo a mano, y por qué una arrow function nunca tiene ese problema.