Tengo un objeto x
. Me gustaría copiarlo como objetoy
, de modo que los cambios y
no se modifiquen x
. Me di cuenta de que copiar objetos derivados de objetos JavaScript incorporados dará como resultado propiedades adicionales no deseadas. Esto no es un problema, ya que estoy copiando uno de mis propios objetos construidos literalmente.
¿Cómo clono correctamente un objeto JavaScript?
javascript
clone
javascript-objects
sonido_tipo
fuente
fuente
mObj=JSON.parse(JSON.stringify(jsonObject));
Object.create(o)
, ¿hace todo lo que el autor pregunta?var x = { deep: { key: 1 } }; var y = Object.create(x); x.deep.key = 2;
Después de hacer esto,y.deep.key
también será 2, por lo tanto, Object.create NO SE PUEDE UTILIZAR para clonar ...Respuestas:
Hacer esto para cualquier objeto en JavaScript no será simple o directo. Te encontrarás con el problema de recoger erróneamente atributos del prototipo del objeto que deberían dejarse en el prototipo y no copiarse en la nueva instancia. Si, por ejemplo, está agregando un
clone
método paraObject.prototype
, como lo muestran algunas respuestas, deberá omitir explícitamente ese atributo. PeroObject.prototype
, ¿qué sucede si hay otros métodos adicionales agregados u otros prototipos intermedios que desconoce? En ese caso, copiará los atributos que no debería, por lo que debe detectar atributos no locales imprevistos con elhasOwnProperty
método.Además de los atributos no enumerables, encontrará un problema más difícil cuando intente copiar objetos que tienen propiedades ocultas. Por ejemplo,
prototype
es una propiedad oculta de una función. Además, el prototipo de un objeto está referenciado con el atributo__proto__
, que también está oculto, y no será copiado por un bucle for / in iterando sobre los atributos del objeto fuente. Creo que__proto__
puede ser específico para el intérprete de JavaScript de Firefox y puede ser algo diferente en otros navegadores, pero se entiende la imagen. No todo es enumerable. Puede copiar un atributo oculto si conoce su nombre, pero no conozco ninguna forma de descubrirlo automáticamente.Otro inconveniente en la búsqueda de una solución elegante es el problema de configurar la herencia del prototipo correctamente. Si el prototipo de su objeto fuente es
Object
, simplemente{}
creará un nuevo objeto general con el que funcionará, pero si el prototipo de la fuente es un descendiente deObject
, entonces le faltarán los miembros adicionales de ese prototipo que omitió usando elhasOwnProperty
filtro, o que estaban en el prototipo, pero no eran enumerables en primer lugar. Una solución podría ser llamar a laconstructor
propiedad del objeto de origen para obtener el objeto de copia inicial y luego copiar los atributos, pero aún así no obtendrá atributos no enumerables. Por ejemplo, unDate
objeto almacena sus datos como un miembro oculto:La cadena de fecha
d1
estará 5 segundos por detrás de la ded2
. Una forma de hacer que uno seaDate
igual a otro es llamar alsetTime
método, pero eso es específico de laDate
clase. No creo que haya una solución general a prueba de balas para este problema, ¡aunque estaría feliz de estar equivocado!Cuando tenía que poner en práctica profunda en general copiar terminé comprometer asumiendo que sólo tendría que copiar una llanura
Object
,Array
,Date
,String
,Number
, oBoolean
. Los últimos 3 tipos son inmutables, por lo que podría realizar una copia superficial y no preocuparme de que cambie. Supuse además que cualquier elemento contenido enObject
oArray
también sería uno de los 6 tipos simples en esa lista. Esto se puede lograr con un código como el siguiente:La función anterior funcionará adecuadamente para los 6 tipos simples que mencioné, siempre que los datos en los objetos y las matrices formen una estructura de árbol. Es decir, no hay más de una referencia a los mismos datos en el objeto. Por ejemplo:
No podrá manejar ningún objeto JavaScript, pero puede ser suficiente para muchos propósitos, siempre y cuando no asuma que solo funcionará para cualquier cosa que le arroje.
fuente
JSON.parse(JSON.stringify([some object]),[some revirer function])
una solución?var cpy = new obj.constructor()
?Si no usa
Date
s, funciones, undefined, regExp o Infinity dentro de su objeto, un revestimiento muy simple esJSON.parse(JSON.stringify(object))
:Esto funciona para todo tipo de objetos que contienen objetos, matrices, cadenas, booleanos y números.
Consulte también este artículo sobre el algoritmo de clonación estructurado de los navegadores que se utiliza al publicar mensajes desde y hacia un trabajador. También contiene una función para la clonación profunda.
fuente
Con jQuery, puede copiar poco con extend :
los cambios posteriores a la
copiedObject
no afectarán a laoriginalObject
, y viceversa.O para hacer una copia profunda :
fuente
var copiedObject = jQuery.extend({},originalObject);
jQuery.extend(true, {}, originalObject);
...subsequent changes to the copiedObject will not affect the originalObject, and vice versa...
? Lamento estar realmente confundido.En ECMAScript 6 existe el método Object.assign , que copia los valores de todas las propiedades propias enumerables de un objeto a otro. Por ejemplo:
Pero tenga en cuenta que los objetos anidados todavía se copian como referencia.
fuente
Object.assign
es el camino a seguir. También es fácil rellenarloPor MDN :
Object.assign({}, a)
JSON.parse(JSON.stringify(a))
No hay necesidad de bibliotecas externas, pero primero debe verificar la compatibilidad del navegador .
fuente
clone
funcionalidad. ver más aquí momentjs.com/docs/#/parsing/moment-cloneHay muchas respuestas, pero ninguna que menciona Object.create de ECMAScript 5, que ciertamente no le da una copia exacta, pero establece la fuente como el prototipo del nuevo objeto.
Por lo tanto, esta no es una respuesta exacta a la pregunta, pero es una solución de una línea y, por lo tanto, elegante. Y funciona mejor para 2 casos:
Ejemplo:
¿Por qué considero que esta solución es superior? Es nativo, por lo tanto, sin bucles ni recursiones. Sin embargo, los navegadores más antiguos necesitarán un polyfill.
fuente
var a = {b:'hello',c:{d:'world'}}, b = Object.create(a); a == b /* false */; a.c == b.c /* true */;
Object.create
señala las propiedades del padre a través de referencias. Eso significa que si los valores de propiedad del padre cambian, el niño también cambiará. Esto tiene algunos efectos secundarios sorprendentes con matrices anidadas y objetos que podrían conducir a errores difíciles de encontrar en su código si no los conoce: jsbin.com/EKivInO/2 . Un objeto clonado es un objeto completamente nuevo e independiente que tiene las mismas propiedades y valores que el padre, pero no está conectado al padre.Una forma elegante de clonar un objeto Javascript en una línea de código
Un
Object.assign
método es parte del estándar ECMAScript 2015 (ES6) y hace exactamente lo que necesita.Lee mas...
El polyfill para admitir navegadores antiguos:
fuente
Object.assign
toma dos parámetros cuando lavalue
función en el polyfill toma solo un parámetro?arguments
objeto antes). Tengo problemas para encontrarlo aObject()
través de Google ... es un tipo de letra, ¿no?Existen varios problemas con la mayoría de las soluciones en Internet. Así que decidí hacer un seguimiento, que incluye, por qué la respuesta aceptada no debería aceptarse.
situación inicial
Quiero copiar en profundidad un Javascript
Object
con todos sus hijos y sus hijos, etc. Pero como no soy un desarrollador normal, miObject
tiene normalproperties
,circular structures
e inclusonested objects
.Así que creemos un
circular structure
y unnested object
primero.Vamos a juntar todo en un
Object
nombrea
.A continuación, queremos copiar
a
en una variable llamadab
y mutarla.Sabes lo que pasó aquí porque si no, ni siquiera aterrizarías en esta gran pregunta.
Ahora encontremos una solución.
JSON
El primer intento que intenté fue usar
JSON
.No pierdas demasiado tiempo en ello, obtendrás
TypeError: Converting circular structure to JSON
.Copia recursiva (la "respuesta" aceptada)
Echemos un vistazo a la respuesta aceptada.
Se ve bien, ¿eh? Es una copia recursiva del objeto y también maneja otros tipos, como
Date
, pero eso no era un requisito.Recursión y
circular structures
no funciona bien juntos ...RangeError: Maximum call stack size exceeded
solución nativa
Después de discutir con mi compañero de trabajo, mi jefe nos preguntó qué pasó y encontró una solución simple después de buscar en Google. Se llama
Object.create
.Esta solución se agregó a Javascript hace algún tiempo e incluso se maneja
circular structure
.... y ves, no funcionaba con la estructura anidada adentro.
polyfill para la solución nativa
Hay un polyfill para
Object.create
el navegador anterior como el IE 8. Es algo como lo recomienda Mozilla, y por supuesto, no es perfecto y da como resultado el mismo problema que la solución nativa .Lo he puesto
F
fuera del alcance para que podamos echar un vistazo a lo queinstanceof
nos dice.Mismo problema que la solución nativa , pero un poco peor de salida.
la mejor (pero no perfecta) solución
Al investigar, encontré una pregunta similar ( en Javascript, al realizar una copia profunda, ¿cómo evito un ciclo, debido a que una propiedad es "esto"? ) A esta, pero con una solución mucho mejor.
Y echemos un vistazo a la salida ...
Los requisitos coinciden, pero todavía hay algunos problemas menores, incluido el cambio
instance
denested
ycirc
haciaObject
.conclusión
La última solución que utiliza recursividad y un caché, puede no ser la mejor, pero es una copia profunda real del objeto. Maneja sencilla
properties
,circular structures
ynested object
, pero se hace un lío la instancia de ellos durante la clonación.jsfiddle
fuente
Si está de acuerdo con una copia superficial, la biblioteca underscore.js tiene un método de clonación .
o puedes extenderlo como
fuente
OK, imagina que tienes este objeto a continuación y quieres clonarlo:
o
la respuesta depende principalmente de qué ECMAscript está usando,
ES6+
simplemente puede usarObject.assign
para hacer el clon:o usando un operador de propagación como este:
Pero si usa
ES5
, puede usar algunos métodos, peroJSON.stringify
asegúrese de no usar una gran cantidad de datos para copiar, pero podría ser una línea útil en muchos casos, algo como esto:fuente
big chunk of data
que equivaldría? 100kb? 100MB? ¡Gracias!Object.assign
hace una copia superficial (al igual que la propagación, @Alizera)Una solución particularmente poco elegante es usar la codificación JSON para hacer copias profundas de objetos que no tienen métodos miembros. La metodología es codificar JSON su objeto de destino, luego al decodificarlo, obtiene la copia que está buscando. Puede decodificar tantas veces como desee para hacer tantas copias como necesite.
Por supuesto, las funciones no pertenecen a JSON, por lo que esto solo funciona para objetos sin métodos miembro.
Esta metodología fue perfecta para mi caso de uso, ya que estoy almacenando blobs JSON en un almacén de valores clave, y cuando se exponen como objetos en una API de JavaScript, cada objeto en realidad contiene una copia del estado original del objeto, por lo que puede calcular el delta después de que la persona que llama ha mutado el objeto expuesto.
fuente
{ 'foo': function() { return 1; } }
es un objeto construido literalmente.Simplemente puede usar una propiedad de propagación para copiar un objeto sin referencias. Pero tenga cuidado (vea los comentarios), la 'copia' está justo en el nivel más bajo de objeto / matriz. ¡Las propiedades anidadas siguen siendo referencias!
Clon completo:
Clon con referencias en segundo nivel:
JavaScript en realidad no admite clones profundos de forma nativa. Use una función de utilidad. Por ejemplo Ramda:
fuente
const first = {a: 'foo', b: 'bar'}; const second = {...{a} = first}
Para aquellos que usan AngularJS, también hay un método directo para clonar o extender los objetos en esta biblioteca.
o
Más en la documentación de angular.copy ...
fuente
Aquí hay una función que puede usar.
fuente
new
. La respuesta aceptada no.La respuesta de R. Levy está casi completa, aquí está mi pequeña contribución: hay una manera de manejar referencias recursivas , vea esta línea
if(this[attr]==this) copy[attr] = copy;
Si el objeto es un elemento DOM XML, debemos usar cloneNode en su lugar
if(this.cloneNode) return this.cloneNode(true);
Inspirado por el exhaustivo estudio de A.Levy y el enfoque de creación de prototipos de Calvin, ofrezco esta solución:
Ver también la nota de Andy Burke en las respuestas.
fuente
Date.prototype.clone = function() {return new Date(+this)};
De este artículo: Cómo copiar matrices y objetos en Javascript por Brian Huisman:
fuente
var copiedObj = Object.create(obj);
una buena manera también?En ES-6 simplemente puede usar Object.assign (...). Ex:
Una buena referencia está aquí: https://googlechrome.github.io/samples/object-assign-es6/
fuente
let obj = {person: 'Thor Odinson'}; let clone = Object.assign({}, obj); clone.title = "Whazzup";
)obj
propiedades de las propiedades están clonados. Los valores de propiedad que son Objetos en sí mismos no serán clonados.En ECMAScript 2018
Tenga en cuenta que los objetos anidados todavía se copian como referencia.
fuente
const objDeepClone = JSON.parse(JSON.stringify(obj));
Usando Lodash:
fuente
_.cloneDeep(x)
ya que esencialmente es lo mismo que arriba, pero se lee mejor.Interesado en clonar objetos simples:
JSON.parse(JSON.stringify(json_original));
Fuente: ¿Cómo copiar un objeto JavaScript a una nueva variable NO por referencia?
fuente
Puede clonar un objeto y eliminar cualquier referencia del anterior utilizando una sola línea de código. Simplemente haz:
Para los navegadores / motores que actualmente no admiten Object.create, puede usar este polyfill:
fuente
Object.create(...)
parece definitivamente el camino a seguir.Object.hasOwnProperty
? De esa forma, la gente sabe cómo evitar buscar el enlace del prototipo.text
miembro en obj2. No está haciendo una copia, solo difiere de la cadena del prototipo cuando no se encuentra un miembro en obj2.Nueva respuesta a una vieja pregunta! Si tiene el placer de usar ECMAScript 2016 (ES6) con Spread Syntax , es fácil.
Esto proporciona un método limpio para una copia superficial de un objeto. Hacer una copia profunda, lo que significa hacer una nueva copia de cada valor en cada objeto anidado recursivamente, requiere una de las soluciones más pesadas anteriores.
JavaScript sigue evolucionando.
fuente
var obj = {'key1': 'value1'};
var array = [...obj]; // TypeError: obj is not iterable
Solución ES6 si desea clonar (superficialmente) una instancia de clase y no solo un objeto de propiedad.
fuente
let cloned = Object.assign({}, obj)
?Creo que hay una respuesta simple y funcional. En la copia profunda hay dos preocupaciones:
Por lo tanto, creo que una solución simple será primero serializar y deserializar y luego asignarle también funciones de copia.
Aunque esta pregunta tiene muchas respuestas, espero que esta también ayude.
fuente
cloneDeep
.Para una copia profunda y un clon, JSON.stringify luego JSON.parse el objeto:
fuente
Esta es una adaptación del código de A. Levy para manejar también la clonación de funciones y referencias múltiples / cíclicas; lo que esto significa es que si dos propiedades en el árbol que se clona son referencias del mismo objeto, el árbol de objetos clonado tendrá estas las propiedades apuntan a uno y el mismo clon del objeto referenciado. Esto también resuelve el caso de dependencias cíclicas que, si no se controla, conduce a un bucle infinito. La complejidad del algoritmo es O (n)
Algunas pruebas rápidas
fuente
Solo quería agregar a todas las
Object.create
soluciones en esta publicación, que esto no funciona de la manera deseada con nodejs.En Firefox el resultado de
es
{test:"test"}
.En nodejs es
fuente
Object.hasOwnProperty
para verificar si posee la matriz o no. Sí, esto agrega complejidad adicional para lidiar con la herencia prototípica.fuente
if(!src && typeof src != "object"){
. Creo que debería ser||
no&&
.Como mindeavor declaró que el objeto que se va a clonar es un objeto 'construido literalmente', una solución podría ser simplemente generar el objeto varias veces en lugar de clonar una instancia del objeto:
fuente
He escrito mi propia implementación. No estoy seguro si cuenta como una mejor solución:
La siguiente es la implementación:
fuente