Spread y rest en objetos JavaScript: copias y merge | Nicolás Garzón
El operador ... puede expandir propiedades o agrupar las que sobran. Su significado depende del lugar donde aparece.
Expande propiedades dentro de un objeto nuevo.
JavaScript
Copiar const user = {
name : "Nicolás" ,
role : "developer" ,
} ;
const copy = {
... user,
} ; Agrupa las propiedades restantes durante destructuring.
JavaScript
Copiar const {
role,
... userWithoutRole
} = user; JavaScript
Copiar const defaults = {
theme : "light" ,
pageSize : 20 ,
} ;
const settings = {
... defaults,
theme : "dark" ,
} ; JavaScript
Copiar {
theme : "dark" ,
pageSize : 20 ,
} Cuando una clave aparece varias veces, la última escritura gana.
JavaScript
Copiar const settings = {
theme : "dark" ,
... defaults,
} ; Ahora defaults.theme sobrescribe "dark" y el resultado usa "light".
Una forma frecuente de combinar defaults con opciones recibidas es:
JavaScript
Copiar function createSettings ( options = { } ) {
return {
... defaults,
... options,
} ;
} Las opciones del usuario tienen prioridad porque aparecen después.
JavaScript
Copiar const original = {
name : "Keyboard" ,
} ;
const copy = {
... original,
} ;
original === copy; El objeto exterior tiene una identidad nueva.
Pero las referencias anidadas se copian, no se duplican.
JavaScript
Copiar const original = {
details : {
brand : "KeyCo" ,
} ,
} ;
const copy = {
... original,
} ;
original. details === copy. details; Por eso spread realiza una copia superficial .
JavaScript
Copiar const updatedProduct = {
... product,
price : 150 ,
} ; product conserva su precio anterior y updatedProduct recibe el nuevo.
Para una propiedad anidada también debes copiar el nivel interior.
JavaScript
Copiar const updatedUser = {
... user,
profile : {
... user. profile,
city : "Bogotá" ,
} ,
} ; Si omites el spread interior:
JavaScript
Copiar const updatedUser = {
... user,
profile : {
city : "Bogotá" ,
} ,
} ; Se reemplaza todo profile y se pierden sus demás propiedades.
Object spread copia propiedades:
Propias.
Enumerables.
Con claves string o symbol.
No copia propiedades heredadas ni no enumerables.
JavaScript
Copiar const base = {
inherited : true ,
} ;
const source = Object. create ( base) ;
source. own = true ;
const copy = {
... source,
} ;
copy. own;
copy. inherited; Si una propiedad es un getter, spread lo ejecuta y guarda el valor obtenido como una propiedad normal.
JavaScript
Copiar const source = {
get total ( ) {
console. log ( "Calculating" ) ;
return 100 ;
} ,
} ;
const copy = {
... source,
} ; Durante la copia se imprime "Calculating". copy.total contiene 100; no conserva el getter.
Tampoco conserva automáticamente atributos como writable o configurable.
JavaScript
Copiar const result = {
... null ,
... undefined ,
} ; En object spread, ambos se ignoran y no agregan propiedades.
Esto es diferente de array spread:
JavaScript
Copiar const values = [ ... undefined ] ; Array spread necesita un iterable.
JavaScript
Copiar const payload = {
name : product. name,
... ( product. description && {
description : product. description,
} ) ,
} ; Si la condición es falsy, no se agregan propiedades útiles.
Una forma más explícita puede ser más fácil de leer:
JavaScript
Copiar const payload = {
name : product. name,
} ;
if ( product. description) {
payload. description = product. description;
} No conviertas spread condicional en un acertijo visual.
JavaScript
Copiar const record = {
id : "record-123" ,
name : "Nicolás" ,
passwordHash : "secret" ,
} ;
const {
passwordHash,
... publicRecord
} = record; publicRecord recibe las propiedades restantes.
Al igual que spread, rest recoge propiedades propias enumerables y crea una copia superficial.
JavaScript
Copiar function removeInternalFields ( record ) {
const {
passwordHash,
resetToken,
... safeRecord
} = record;
return safeRecord;
} Esto no elimina nada del objeto original.
Sin embargo, no es una defensa de seguridad completa. La información sensible ya estuvo en memoria y podría existir en otros lugares. Es una transformación de estructura, no un sistema de autorización.
JavaScript
Copiar const keyToRemove = "passwordHash" ;
const {
[ keyToRemove] : removed,
... rest
} = record; Permite excluir una propiedad cuyo nombre se conoce durante la ejecución.
Ambos pueden combinar propiedades.
JavaScript
Copiar const copyWithSpread = {
... source,
} ;
const copyWithAssign = Object. assign ( { } , source) ; JavaScript
Copiar const target = {
theme : "light" ,
} ;
Object. assign ( target, {
theme : "dark" ,
} ) ;
console. log ( target. theme) ; Spread siempre aparece dentro de la creación de otro objeto literal.
Object.assign utiliza asignación sobre el target y puede ejecutar setters existentes.
Object spread crea propiedades de datos en el objeto nuevo y no utiliza un setter heredado de la misma forma.
Para copias normales, spread suele ser más directo. Object.assign sigue siendo útil cuando necesitas trabajar explícitamente con un objeto target.
JavaScript
Copiar const defaults = {
appearance : {
theme : "light" ,
density : "comfortable" ,
} ,
} ;
const options = {
appearance : {
theme : "dark" ,
} ,
} ;
const settings = {
... defaults,
... options,
} ; JavaScript
Copiar {
appearance : {
theme : "dark" ,
} ,
} density se pierde porque appearance completo fue reemplazado.
Para combinar el nivel interior:
JavaScript
Copiar const settings = {
... defaults,
... options,
appearance : {
... defaults. appearance,
... options. appearance,
} ,
} ; JavaScript
Copiar function createProductUpdate ( currentProduct, changes ) {
return {
... currentProduct,
... changes,
metadata : {
... currentProduct. metadata,
... changes. metadata,
updatedAt : new Date ( ) . toISOString ( ) ,
} ,
} ;
} El orden define la prioridad y cada nivel anidado que debe conservar datos se combina explícitamente.
Confundir spread con rest porque ambos usan ....
Pensar que spread crea una copia profunda.
Colocar los objetos en un orden que sobrescribe el valor correcto.
Olvidar copiar un nivel anidado durante una actualización inmutable.
Esperar que spread copie propiedades heredadas o no enumerables.
Creer que conserva getters, setters y descriptores completos.
Llamar “deep merge” a varios spreads superficiales.
Usar spread condicional tan complejo que oculta la intención.
Suponer que rest elimina propiedades del objeto original.
Spread expande propiedades; rest agrupa las restantes.
La última aparición de una clave tiene prioridad.
Object spread crea un objeto exterior nuevo.
Las referencias anidadas continúan compartidas.
Solo se copian propiedades propias enumerables.
Los getters se evalúan durante spread.
Rest no modifica el objeto original.
Object.assign muta su target.
Combinar objetos con spread sigue siendo una operación superficial.
JavaScript
Copiar const defaults = {
appearance : {
theme : "light" ,
density : "comfortable" ,
} ,
} ;
const settings = {
... defaults,
appearance : {
theme : "dark" ,
} ,
} ; Respuesta density desaparece del nuevo objeto. La propiedad appearance fue reemplazada por completo; spread no combina automáticamente objetos anidados.
Mutabilidad e inmutabilidad explica cuándo un objeto cambia en el mismo lugar, cuándo se crea uno nuevo y por qué la identidad importa.