Ir al contenido principal

Object.keys, values y entries

Introducción

Los objetos son estructuras fundamentales en JavaScript que nos permiten almacenar datos como pares clave-valor. Cuando trabajamos con objetos, frecuentemente necesitamos acceder a sus propiedades o valores de manera eficiente o transformarlos para procesarlos. JavaScript proporciona tres métodos estáticos muy útiles para esto: Object.keys(), Object.values() y Object.entries(). Estos métodos nos facilitan enormemente la extracción de información de los objetos y nos permiten tender un puente entre la programación orientada a objetos y la funcional, permitiéndonos aplicar operaciones propias de arrays a los datos de nuestros objetos.

Métodos estáticos de Object para propiedades

Antes de entrar en detalle, recordemos que un método estático es aquel que se llama directamente sobre la clase (en este caso Object) y no sobre una instancia. Por eso utilizamos la sintaxis Object.keys() en lugar de miObjeto.keys().

Object.keys()

Object.keys() devuelve un array con los nombres de las propiedades enumerables de un objeto, en el mismo orden en que las obtendríamos con un bucle for...in.

const persona = {
    nombre: "Laura",
    edad: 28,
    profesion: "desarrolladora"
};

const propiedades = Object.keys(persona);
console.log(propiedades); // ["nombre", "edad", "profesion"]

Este método es especialmente útil cuando necesitamos conocer qué propiedades tiene un objeto, o cuando queremos iterar sobre ellas de forma controlada.

// Iterando sobre las propiedades de un objeto
const producto = {
    id: "P001",
    nombre: "Teclado mecánico",
    precio: 85,
    stock: 15
};

Object.keys(producto).forEach(propiedad => {
    console.log(`La propiedad ${propiedad} tiene el valor: ${producto[propiedad]}`);
});

// Resultado:
// La propiedad id tiene el valor: P001
// La propiedad nombre tiene el valor: Teclado mecánico
// La propiedad precio tiene el valor: 85
// La propiedad stock tiene el valor: 15

Object.values()

Object.values() devuelve un array con los valores de las propiedades enumerables del objeto, en el mismo orden que Object.keys().

const configuracion = {
    tema: "oscuro",
    notificaciones: true,
    idioma: "es-ES"
};

const valores = Object.values(configuracion);
console.log(valores); // ["oscuro", true, "es-ES"]

Este método es perfecto cuando solo nos interesan los valores almacenados en el objeto y no necesitamos las claves.

// Calculando el valor total de un carrito de compra
const carrito = {
    producto1: 29.99,
    producto2: 12.50,
    producto3: 35.75
};

const total = Object.values(carrito).reduce((suma, precio) => suma + precio, 0);
console.log(`Total a pagar: ${total.toFixed(2)}€`); // Total a pagar: 78.24€

Object.entries()

Object.entries() devuelve un array de arrays, donde cada subarray es un par [clave, valor] de las propiedades enumerables del objeto.

const estudiante = {
    id: "E12345",
    nombre: "Carlos",
    curso: "JavaScript Avanzado"
};

const entradas = Object.entries(estudiante);
console.log(entradas);
// [
//   ["id", "E12345"],
//   ["nombre", "Carlos"],
//   ["curso", "JavaScript Avanzado"]
// ]

Este método es extremadamente útil cuando necesitamos tanto las claves como los valores, y especialmente cuando queremos transformar los objetos en otras estructuras de datos.

// Iterando sobre pares clave-valor
const puntuaciones = {
    Juan: 85,
    Maria: 92,
    Pedro: 78,
    Ana: 96
};

Object.entries(puntuaciones).forEach(([nombre, puntuacion]) => {
    console.log(`${nombre} ha obtenido ${puntuacion} puntos`);
});

// Resultado:
// Juan ha obtenido 85 puntos
// Maria ha obtenido 92 puntos
// Pedro ha obtenido 78 puntos
// Ana ha obtenido 96 puntos

Iteración sobre objetos con estos métodos

Estos métodos son especialmente valiosos cuando los combinamos con los métodos de array como map, filter, o reduce, permitiéndonos tratar los datos de objetos como si fueran arrays.

Ejemplo con map

// Transformando un objeto en otro con valores modificados
const precios = {
    manzana: 1.20,
    pera: 1.50,
    platano: 0.95,
    naranja: 1.10
};

// Aplicar un descuento del 10% a todos los precios
const preciosConDescuento = Object.entries(precios).map(([fruta, precio]) => {
    const precioConDescuento = precio * 0.9;
    return [fruta, precioConDescuento.toFixed(2)];
});

// Convertir de nuevo a objeto
const objetoPreciosConDescuento = Object.fromEntries(preciosConDescuento);
console.log(objetoPreciosConDescuento);
// {
//   manzana: "1.08",
//   pera: "1.35",
//   platano: "0.86",
//   naranja: "0.99"
// }

Ejemplo con filter

// Filtrar productos que estén en oferta
const catalogo = {
    camiseta: { precio: 15, oferta: true },
    pantalon: { precio: 25, oferta: false },
    zapatillas: { precio: 40, oferta: true },
    gorra: { precio: 12, oferta: false }
};

const productosEnOferta = Object.entries(catalogo)
    .filter(([_, producto]) => producto.oferta)
    .map(([nombre, producto]) => ({
        nombre,
        precio: producto.precio
    }));

console.log(productosEnOferta);
// [
//   { nombre: "camiseta", precio: 15 },
//   { nombre: "zapatillas", precio: 40 }
// ]

Transformación entre objetos y arrays

Una de las aplicaciones más poderosas de estos métodos es la capacidad de convertir objetos en arrays y viceversa, lo que nos permite aprovechar lo mejor de ambos mundos.

De objeto a array

const tareas = {
    tarea1: "Hacer la compra",
    tarea2: "Estudiar JavaScript",
    tarea3: "Hacer ejercicio"
};

// Convertir a array de objetos
const arrayTareas = Object.entries(tareas).map(([id, descripcion]) => ({
    id,
    descripcion
}));

console.log(arrayTareas);
// [
//   { id: "tarea1", descripcion: "Hacer la compra" },
//   { id: "tarea2", descripcion: "Estudiar JavaScript" },
//   { id: "tarea3", descripcion: "Hacer ejercicio" }
// ]

De array a objeto

const usuarios = [
    { id: 1, nombre: "Ana", email: "ana@ejemplo.com" },
    { id: 2, nombre: "Luis", email: "luis@ejemplo.com" },
    { id: 3, nombre: "Elena", email: "elena@ejemplo.com" }
];

// Convertir a objeto usando id como clave
const objetoUsuarios = usuarios.reduce((obj, usuario) => {
    obj[usuario.id] = usuario;
    return obj;
}, {});

console.log(objetoUsuarios);
// {
//   1: { id: 1, nombre: "Ana", email: "ana@ejemplo.com" },
//   2: { id: 2, nombre: "Luis", email: "luis@ejemplo.com" },
//   3: { id: 3, nombre: "Elena", email: "elena@ejemplo.com" }
// }

// También podemos usar Object.fromEntries (ES2019)
const mapeoUsuarios = usuarios.map(usuario => [usuario.id, usuario]);
const objetoUsuarios2 = Object.fromEntries(mapeoUsuarios);

console.log(objetoUsuarios2); // Resultado igual al anterior

Filtrado y mapeo de propiedades

Los métodos que hemos visto son perfectos para filtrar o mapear propiedades de objetos según criterios específicos.

const datosFormulario = {
    nombre: "Miguel",
    email: "miguel@ejemplo.com",
    _token: "abc123def456",
    _timestamp: 1617283945,
    edad: 31,
    direccion: "Calle Principal 42"
};

// Filtrar propiedades privadas (que empiezan con _)
const datosFiltrados = Object.entries(datosFormulario)
    .filter(([clave]) => !clave.startsWith("_"))
    .reduce((obj, [clave, valor]) => {
        obj[clave] = valor;
        return obj;
    }, {});

console.log(datosFiltrados);
// {
//   nombre: "Miguel",
//   email: "miguel@ejemplo.com",
//   edad: 31,
//   direccion: "Calle Principal 42"
// }

Comparación de objetos

JavaScript no tiene un método integrado para comparar objetos directamente, pero usando estos métodos podemos crear funciones para hacerlo.

// Función para comparar si dos objetos tienen las mismas propiedades y valores
function sonObjetosIguales(obj1, obj2) {
    // Comparar número de propiedades
    if (Object.keys(obj1).length !== Object.keys(obj2).length) {
        return false;
    }
    
    // Comparar cada propiedad y valor
    return Object.keys(obj1).every(key => {
        // Si es un objeto anidado, comparación recursiva
        if (typeof obj1[key] === 'object' && obj1[key] !== null && 
            typeof obj2[key] === 'object' && obj2[key] !== null) {
            return sonObjetosIguales(obj1[key], obj2[key]);
        }
        return obj1[key] === obj2[key];
    });
}

const objeto1 = { a: 1, b: 2, c: { d: 3 } };
const objeto2 = { a: 1, b: 2, c: { d: 3 } };
const objeto3 = { a: 1, b: 2, c: { d: 4 } };

console.log(sonObjetosIguales(objeto1, objeto2)); // true
console.log(sonObjetosIguales(objeto1, objeto3)); // false

Resumen

Los métodos Object.keys(), Object.values() y Object.entries() son herramientas fundamentales para la manipulación de objetos en JavaScript moderno. Nos permiten:

  • Extraer propiedades, valores o pares clave-valor de objetos en forma de arrays
  • Iterar sobre objetos de manera más clara y consistente
  • Transformar objetos en arrays y viceversa
  • Aplicar operaciones funcionales como map, filter y reduce a los datos de objetos
  • Filtrar y mapear propiedades según criterios específicos
  • Implementar comparaciones personalizadas entre objetos

Estos métodos han simplificado enormemente la forma en que trabajamos con objetos en JavaScript, haciendo que nuestra código sea más limpio, expresivo y funcional. Son particularmente útiles en la programación moderna, especialmente cuando trabajamos con datos provenientes de APIs o cuando necesitamos transformar estructuras de datos.

En el próximo artículo, exploraremos la poderosa técnica de desestructuración de objetos y arrays, que complementa perfectamente los métodos que hemos aprendido hoy y nos permite escribir código aún más conciso y expresivo.