Object.assign() y Object.create(): Copiar y Crear Objetos
Aprende a usar Object.assign() para copiar propiedades y Object.create() para establecer prototipos y crear objetos con herencia personalizada.
TL;DR - Resumen rápido
- Object.assign() copia propiedades enumerables entre objetos (copia superficial)
- Object.create() crea un nuevo objeto con un prototipo específico
- Object.assign() modifica el objeto destino y retorna su referencia
- Object.create() establece herencia real, assign() solo copia valores
- La copia superficial de assign() no clona objetos anidados (se copian por referencia)
- Ambos métodos se combinan frecuentemente para crear objetos con herencia y propiedades
Introducción
Object.assign() y Object.create() son dos métodos fundamentales para trabajar con objetos en JavaScript, pero tienen propósitos completamente diferentes. Object.assign() se usa para copiar propiedades de uno o más objetos fuente a un objeto destino, mientras que Object.create() crea un nuevo objeto estableciendo su prototipo, lo que permite implementar herencia prototípica de forma explícita.
Dos herramientas, dos propósitos
Object.assign() es para COPIAR propiedades (clonación, merge), mientras que Object.create() es para ESTABLECER HERENCIA (cadena de prototipos). Aunque son diferentes, frecuentemente se usan juntos en patrones avanzados.
Object.assign() - Sintaxis Básica
Object.assign() toma un objeto destino y una o más fuentes, copiando todas las propiedades enumerables y propias de las fuentes al destino. Importante: modifica y retorna el objeto destino, no crea uno nuevo a menos que uses un objeto vacío como destino.
El patrón Object.assign(, fuente) es muy común para clonar objetos, creando una copia superficial del objeto fuente. Si hay múltiples fuentes, las propiedades se copian de izquierda a derecha, y las propiedades duplicadas son sobrescritas por las fuentes posteriores. Solo se copian propiedades enumerables y propias (hasOwnProperty), las heredadas del prototipo se ignoran.
Destino es modificado
Object.assign(destino, fuente) modifica directamente destino y lo retorna. Para evitar modificar el original, usa un objeto vacío como primer argumento: Object.assign(, original).
Object.create() - Sintaxis Básica
Object.create() crea un nuevo objeto usando el objeto proporcionado como su prototipo. Esto establece la cadena de prototipos de forma explícita, permitiendo que el nuevo objeto herede propiedades y métodos del prototipo sin tenerlas como propiedades propias.
Object.create() es fundamental para implementar herencia prototípica sin usar clases ES6. Puedes crear objetos con prototipo null para diccionarios puros sin contaminación de Object.prototype, o establecer cualquier objeto como prototipo para herencia personalizada. El segundo parámetro opcional permite definir propiedades con descriptores completos (writable, enumerable, configurable).
Herencia verdadera
Con Object.create(proto), el nuevo objeto NO tiene las propiedades como propias (hasOwnProperty = false). Las hereda del prototipo, lo que significa que cambios en el prototipo afectan a todos los objetos que heredan de él.
Copia Superficial vs Profunda
Object.assign() realiza una copia superficial (shallow copy), lo que significa que solo copia las referencias de los objetos anidados, no sus valores. Esto puede causar efectos secundarios inesperados cuando modificas objetos o arrays anidados en la copia, ya que también modificarás el original.
Para evitar el problema de la copia superficial, puedes usar técnicas de copia profunda (deep copy): clonación manual con spread operator para cada nivel, JSON.parse(JSON.stringify()) para objetos serializables simples, o funciones recursivas personalizadas. Cada técnica tiene sus limitaciones: JSON pierde funciones, Dates y otros tipos especiales, mientras que la recursión manual requiere manejar casos especiales como referencias circulares.
Cuidado con objetos anidados
Object.assign() NO clona objetos anidados. Los copia por referencia, lo que significa que modificar obj.nested.value en la copia también modificará el original. Usa técnicas de copia profunda cuando necesites independencia total.
Diferencias entre assign() y create()
Aunque ambos métodos trabajan con objetos, sus propósitos son completamente diferentes. Object.assign() copia propiedades como propiedades propias del destino, mientras que Object.create() establece un prototipo del cual el nuevo objeto hereda. Esta diferencia fundamental afecta cómo se comportan hasOwnProperty, Object.keys, y cómo los cambios en el objeto fuente/prototipo afectan al objeto resultante.
Con Object.assign(), las propiedades se convierten en propiedades propias del objeto destino (hasOwnProperty = true), y modificar el objeto fuente después no afecta la copia. Con Object.create(), las propiedades permanecen en el prototipo (hasOwnProperty = false), y cambios en el prototipo SÍ afectan a todos los objetos que heredan de él. assign() es para clonación/merge, create() es para herencia.
Cuándo usar cada uno
Usa Object.assign() para clonar objetos, fusionar configuraciones, o copiar propiedades. Usa Object.create() para establecer herencia prototípica, crear objetos sin Object.prototype (con null), o implementar patrones de herencia sin clases.
Patrones Comunes
Object.assign() y Object.create() son la base de varios patrones de diseño importantes en JavaScript. Desde configuración por defecto y actualización inmutable de estado, hasta mixins, factories con prototipos, y objetos extensibles, estos métodos proporcionan las herramientas necesarias para crear arquitecturas flexibles y mantenibles.
Los patrones más comunes incluyen: configuración por defecto con Object.assign(, defecto, opciones), actualización inmutable creando nuevos objetos en lugar de modificar existentes, mixins para composición de funcionalidad, factories que combinan create() para herencia con assign() para propiedades, decoradores que agregan funcionalidad, y objetos con prototipo null para diccionarios seguros sin contaminación de prototype.
Combinación poderosa
El patrón Object.assign(Object.create(proto), propiedades) combina lo mejor de ambos: herencia prototípica de create() con propiedades propias de assign(). Es la base de muchos factories y sistemas de plugins.
Casos Especiales y Limitaciones
Tanto Object.assign() como Object.create() tienen casos especiales y limitaciones importantes. Object.assign() evalúa getters y los convierte en valores simples, copia símbolos pero no propiedades no-enumerables, y no puede copiar propiedades del prototipo. Object.create() con null crea objetos sin métodos de Object.prototype, y su segundo parámetro permite definir propiedades con descriptores completos.
Los casos especiales incluyen: getters/setters que se evalúan durante la copia con assign(), propiedades símbolo que SÍ se copian, propiedades no-enumerables que NO se copian, propiedades heredadas que se ignoran, errores durante la copia que detienen el proceso, y objetos con prototipo null que son inmunes a prototype pollution. Object.create() con descriptores permite control fino sobre writable, enumerable y configurable.
Preservar descriptores
Para copiar getters/setters y otros descriptores de propiedades, usa Object.defineProperties(destino, Object.getOwnPropertyDescriptors(fuente)). Object.assign() evalúa los getters y copia solo sus valores retornados.
Ejemplo Práctico: Sistema de Gestión de Productos
Este ejemplo completo demuestra cómo combinar Object.assign() y Object.create() para crear un sistema de gestión de productos con herencia prototípica, factories, clonación, configuración por defecto, y actualización inmutable. El sistema incluye productos digitales y físicos que heredan de un prototipo base común.
El sistema usa Object.create() para establecer cadenas de prototipos (productoBase → productoDigitalBase/productoFisicoBase), Object.assign() para fusionar configuración por defecto con datos del producto, y combinaciones de ambos en los factories para crear objetos con herencia y propiedades específicas. El catálogo demuestra clonación, búsqueda, estadísticas y actualización inmutable de configuración, todo usando estos dos métodos fundamentales.
Arquitectura completa
Este ejemplo muestra cómo Object.assign() y Object.create() son la base de arquitecturas orientadas a objetos en JavaScript sin usar clases ES6, implementando herencia, polimorfismo, composición y encapsulación.
Resumen: Object.assign() y Object.create()
Conceptos principales:
- •Object.assign() copia propiedades como propias, create() establece prototipo
- •assign() modifica el destino y retorna su referencia
- •La copia de assign() es superficial: objetos anidados se copian por referencia
- •create() establece herencia real: cambios en proto afectan a herederos
- •assign() ignora propiedades heredadas y no-enumerables
- •create(null) crea objetos sin Object.prototype (diccionarios puros)
Mejores prácticas:
- •Usa Object.assign({}, obj) para clonar superficialmente
- •Combina assign(create(proto), props) para herencia + propiedades
- •Para copia profunda usa estructuredClone() o recursión manual
- •Usa create(null) para diccionarios inmunes a prototype pollution
- •Preserva descriptores con Object.defineProperties + getOwnPropertyDescriptors
- •Prefiere const config = {...defecto, ...opciones} (spread) para claridad