Clonación de objetos complejos en JavaScript con structuredClone

Cómo clonar objetos con estructuras anidadas en JavaScript, comparando técnicas tradicionales con structuredClone().

clonar-objeto-structured-clone-javascript

En JavaScript, copiar objetos que contienen estructuras anidadas siempre ha sido un tema peliagudo. Las soluciones habituales, como usar el operador spread o la combinación de JSON.stringify() y JSON.parse(), tienen limitaciones que pueden generar errores según qué objetos internos contengan. Desde Marzo de 2022 ya se puede usar la función structuredClone() en todos los navegadores habituales, un método que busca solventar estos problemas en muchos casos.

Aunque usar el operador spread ({...obj}) resulta práctico para copiar propiedades a nivel superficial, su copia es shallow; es decir, si el objeto contiene subobjetos, éstos se mantienen referenciados. Por ejemplo:

const original = { a: 1, b: { c: 2 } };
const copia = { ...original };
copia.b.c = 3;
console.log(original.b.c); // Imprime 3 en vez de 2, pues el objeto anidado sigue siendo el mismo

Otra estrategia popular es combinar JSON.stringify() y JSON.parse(). Esta técnica permite copiar objetos de forma profunda, pero presenta inconvenientes:

  • Referencias circulares: La presencia de ciclos en la estructura genera un error durante la conversión TypeError: Converting circular structure to JSON.
  • Valores especiales: Las propiedades con valores undefined y las funciones se omiten.
const objeto = {
a: 1,
b: { c: 2 },
d: undefined,
e: () => console.log('Hola')
};
objeto.f = objeto
try {
const clon = JSON.parse(JSON.stringify(objeto));
console.log(clon);
} catch (error) {
console.error('Error al clonar el objeto:', error);
}

Con la llegada de structuredClone(), se introduce un método que realiza una clonación profunda utilizando el algoritmo de clonación estructurada propio de la plataforma. Este método permite copiar objetos con datos cíclicos sin provocar errores y conserva valores que JSON.parse+stringify descarta, como undefined. Sin embargo, no clona funciones; si el objeto contiene alguna, se lanzará un error.

const objetoValido = { a: 1, b: { c: 2 }, d: undefined };
objetoValido.e = objetoValido;
const clon = structuredClone(objetoValido);
console.log(clon);
// Salida: { a: 1, b: { c: 2 }, d: undefined }
const objetoConFuncion = {
a: 1,
b: () => console.log('Esto no se puede clonar')
};
try {
const clonErroneo = structuredClone(objetoConFuncion);
} catch (error) {
console.error('No se pueden clonar funciones:', error);
}

En resumen

En conclusión, structuredClone() ofrece una alternativa a tener en cuenta para copiar objetos complejos en JavaScript, especialmente cuando se trata de estructuras anidadas y datos cíclicos. Si bien supera algunas de las limitaciones del operador spread y de la técnica con JSON Parse y Stringify, es importante tener en cuenta sus restricciones, principalmente en lo que respecta a funciones. La elección del método dependerá del tipo de objeto a clonar y de los requisitos específicos del momento.