¿Cuál es la forma más eficiente de clonar un objeto JavaScript? He visto que se usa obj = eval(uneval(o));
, pero eso no es estándar y sólo lo soporta Firefox.
He hecho cosas como obj = JSON.parse(JSON.stringify(o));
pero cuestiono la eficiencia.
También he visto funciones de copia recursiva con varios fallos.
Me sorprende que no exista una solución canónica.
Se llama "clonación estructurada", funciona experimentalmente en Node 11 y posteriores, y es de esperar que aterrice en los navegadores. Ver esta respuesta para más detalles.
Si no utilizas Date
s, funciones, undefined
, Infinity
, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays u otros tipos complejos dentro de tu objeto, un one liner muy simple para clonar en profundidad un objeto es:
JSON.parse(JSON.stringify(object))
begin snippet: js hide: false console: true babel: false -->
const a = {
string: 'string',
number: 123,
bool: false,
nul: null,
date: new Date(), // stringified
undef: undefined, // lost
inf: Infinity, // forced to 'null'
re: /.*/, // lost
}
console.log(a);
console.log(typeof a.date); // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date); // result of .toISOString()
Consulte Corban's answer para ver los puntos de referencia.
Dado que la clonación de objetos no es trivial (tipos complejos, referencias circulares, funciones, etc.), la mayoría de las bibliotecas principales proporcionan funciones para clonar objetos. No reinventes la rueda - si ya estás usando una biblioteca, comprueba si tiene una función de clonación de objetos. Por ejemplo,
cloneDeep
; puede ser importado por separado a través del módulo lodash.clonedeep y es probablemente su mejor opción si no está utilizando una biblioteca que proporcione una función de clonación profundaangular.copy
jQuery.extend(true, { }, oldObject)
; .clone()
sólo clona elementos del DOMPara completar la información, ten en cuenta que ES6 ofrece dos mecanismos de copia superficial: Object.assign()
y el operador spread.
Si no hubiera ninguna incorporada, podrías intentarlo:
function clone(obj) {
if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
return obj;
if (obj instanceof Date)
var temp = new obj.constructor(); //or new Date(obj);
else
var temp = obj.constructor();
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
obj['isActiveClone'] = null;
temp[key] = clone(obj[key]);
delete obj['isActiveClone'];
}
}
return temp;
}