... donde cada objeto también tiene referencias a otros objetos dentro de la misma matriz?
Cuando se me ocurrió este problema, pensé en algo como
var clonedNodesArray = nodesArray.clone()
existiría y buscó información sobre cómo clonar objetos en javascript. Encontré una pregunta en StackOverflow (respondida por el mismo @JohnResig) y señaló que con jQuery podrías hacer
var clonedNodesArray = jQuery.extend({}, nodesArray);
para clonar un objeto. Sin embargo, probé esto, esto solo copia las referencias de los objetos en la matriz. Entonces si yo
nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"
el valor de ambos nodeArray [0] y clonedNodesArray [0] resultará ser "verde". Entonces intenté
var clonedNodesArray = jQuery.extend(true, {}, nodesArray);
que copia en profundidad un objeto, pero recibí mensajes de " demasiada recursividad " y " desbordamiento de la pila de control " de Firebug y Opera Dragonfly respectivamente.
¿Como lo harias? ¿Es esto algo que ni siquiera debería hacerse? ¿Hay alguna forma reutilizable de hacer esto en Javascript?
fuente
Siempre que sus objetos contengan contenido serializable JSON (sin funciones, no
Number.POSITIVE_INFINITY
, etc.) no es necesario que ningún bucle clone matrices u objetos. Aquí hay una solución pura de una línea de vainilla.Para resumir los comentarios a continuación, la principal ventaja de este enfoque es que también clona el contenido de la matriz, no solo la matriz misma. Las desventajas principales son su límite de trabajar solo en contenido serializable JSON, y su rendimiento (que es significativamente peor que un
slice
enfoque basado).fuente
null
yundefined
serán problemas, ya que JSON no los admite). Además, es una operación mucho menos eficiente queold_array.slice(0);
, que debería funcionar mejor y más rápido.Resolví la clonación de una matriz de objetos con Object.assign
o incluso más corto con sintaxis extendida
fuente
{}
connew Dinosaur()
.Si todo lo que necesita es una copia superficial, una forma realmente fácil es:
fuente
0
, puedes llamar.slice()
al menos en Chrome de todos modosslice
será una nueva matriz pero contendrá las referencias a los objetos de la matriz original.La mejor y más actualizada forma de hacer este clon es la siguiente:
Uso del
...
operador de propagación ES6.Aquí está el ejemplo más simple:
De esta forma, distribuimos la matriz en valores individuales y la colocamos en una nueva matriz con el operador [].
Aquí hay un ejemplo más extenso que muestra las diferentes formas en que funciona:
fuente
Esto funciona para mi:
Y si necesita una copia profunda de los objetos en la matriz:
fuente
fuente
JSON.parse(JSON.stringify(origArray));
JSON.parse(JSON.stringify(origArray));
Definitivamente es la solución más simple.El mapa creará una nueva matriz a partir de la anterior (sin referencia a la anterior) y dentro del mapa creará un nuevo objeto e iterará sobre las propiedades (claves) y asignará valores del antiguo objeto de matriz a las propiedades correspondientes al nuevo objeto.
Esto creará exactamente la misma matriz de objetos.
fuente
Puedo tener una manera simple de hacer esto sin tener que hacer una dolorosa recursión y sin conocer todos los detalles más finos del objeto en cuestión. Usando jQuery, simplemente convierta su objeto a JSON usando jQuery
$.toJSON(myObjectArray)
, luego tome su cadena JSON y evalúela nuevamente en un objeto. BAM! ¡Hecho y hecho! Problema resuelto. :)fuente
eval
.eval()
en absoluto. Es un riesgo de seguridad.Estoy respondiendo esta pregunta porque no parece haber una solución simple y explícita al problema de "clonar una matriz de objetos en Javascript":
Esta solución itera los valores de la matriz, luego itera las claves del objeto, guarda la última en un nuevo objeto y luego empuja ese nuevo objeto a una nueva matriz.
Ver jsfiddle . Nota: un simple
.slice()
o[].concat()
no es suficiente para los objetos dentro de la matriz.fuente
JQuery extend está funcionando bien, solo necesita especificar que está clonando una matriz en lugar de un objeto ( observe el [] en lugar de {} como parámetro para el método extendido ):
fuente
Este método es muy simple y puede modificar su clon sin modificar la matriz original.
fuente
[...oldArray]
yoldArray.slice(0)
hacer una copia superficial de un nivel profundo. Así que esto es súper útil, pero no es un clon completo real.lodash.clonedeep
desde npmComo mencionó Daniel Lew, los gráficos cíclicos tienen algunos problemas. Si tuviera este problema, agregaría
clone()
métodos especiales a los objetos problemáticos o recordaría qué objetos ya he copiado.Lo haría con una variable
copyCount
que aumenta en 1 cada vez que copie su código. SecopyCount
copia un objeto que tiene un proceso de copia inferior al actual. De lo contrario, se debe hacer referencia a la copia que ya existe. Esto hace que sea necesario vincular desde el original a su copia.Todavía hay un problema: la memoria. Si tiene esta referencia de un objeto a otro, es probable que el navegador no pueda liberar esos objetos, ya que siempre se hace referencia desde algún lugar. Tendría que hacer un segundo pase donde establezca todas las referencias de copia a Null. (Si hace esto, no tendría que tener un
copyCount
booleanoisCopied
, pero sería suficiente, ya que puede restablecer el valor en la segunda pasada).fuente
Array.slice se puede usar para copiar una matriz o parte de una matriz ... http://www.devguru.com/Technologies/Ecmascript/Quickref/Slice.html Esto funcionaría con cadenas y números ... - cambiando una cadena en una matriz no afectaría a la otra, pero los objetos solo se copian por referencia, por lo que los cambios a los objetos referenciados en una matriz afectarían a la otra matriz.
Aquí hay un ejemplo de un administrador de deshacer de JavaScript que podría ser útil para esto: http://www.ridgway.co.za/archive/2007/11/07/simple-javascript-undo-manager-for-dtos.aspx
fuente
Mi acercamiento:
me da un clon agradable, limpio y profundo de la matriz original, sin que ninguno de los objetos haga referencia al original :-)
fuente
Lodash tiene una
cloneDeep
función para este propósito:fuente
Si desea implementar un clon profundo, use JSON.parse (JSON.stringify (su {} o []))
fuente
olvide eval () (es la característica más mal utilizada de JS y hace que el código sea lento) y slice (0) (funciona solo para tipos de datos simples)
Esta es la mejor solución para mí:
fuente
Estaba bastante frustrado por este problema. Aparentemente, el problema surge cuando envía una matriz genérica al método $ .extend. Entonces, para solucionarlo, agregué una pequeña comprobación, y funciona perfectamente con matrices genéricas, matrices jQuery y cualquier objeto.
Invocar usando:
fuente
Esto copia profundamente los arrays, objetos, valores nulos y otros valores escalares, y también copia profundamente cualquier propiedad en funciones no nativas (lo cual es bastante poco común pero posible). (Para mayor eficiencia, no intentamos copiar propiedades no numéricas en las matrices).
fuente
Uso el nuevo método ECMAScript 6 Object.assign :
El primer argumento de este método es la matriz que se actualizará, pasamos un objeto vacío porque queremos tener un nuevo objeto.
También podemos usar esta sintaxis, que es la misma pero más corta:
fuente
Podemos inventar un método de matriz recursiva simple para clonar matrices multidimensionales. Si bien los objetos dentro de las matrices anidadas mantienen su referencia a los objetos correspondientes en la matriz fuente, las matrices no lo harán.
fuente
En JavaScript, la copia de matriz y objeto cambia los valores de origen, por lo que la copia profunda es la solución para esto.
Una copia profunda significa en realidad crear una nueva matriz y copiar sobre los valores, ya que pase lo que pase nunca afectará al origen.
JSON.parse
yJSON.stringify
es la mejor y más simple forma de copiar en profundidad. ElJSON.stringify()
método convierte un valor de JavaScript en una cadena JSON. ElJSON.parse()
método analiza una cadena JSON, construyendo el valor de JavaScript u objeto descrito por la cadena.// Deep Clone
Para más detalles: lea aquí
fuente
con jQuery:
fuente
El siguiente código realizará una copia recursiva profunda de los objetos y la matriz :
Fuente
fuente
arguments.callee
no está disponible en modo estricto y tiene problemas de rendimiento de lo contrario.Algunas formas elegantes para la clonación profunda en javascript
https://mootools.net/core/docs/1.6.0/Types/Object
https://scotch.io/bar-talk/copying-objects-in-javascript
1) Un método Javascript vainilla para clonar objetos
2) Una explotación inteligente de la biblioteca JSON para clonar objetos en profundidad
3) Uso de la función $ .extend () de jQuery
4) Uso de la función clonar () de Mootools para clonar objetos
fuente
Creo que logró escribir un método genérico de clonación profunda de cualquier estructura de JavaScript, principalmente,
Object.create
que es compatible con todos los navegadores modernos. El código es así:fuente
Object.create
se trataráitem
como el prototipo del objeto, pero eso es diferente de la clonación. Siitem
se modifica, los cambios se reflejarán en su "clon" y viceversa. Este enfoque no funciona.Para clonar los objetos también, solo iba a sugerir ECMAScript 6
reduce()
:Pero, francamente, me gusta aún más la respuesta de @dinodsaurus. Solo estoy poniendo esta versión aquí como otra opción, pero personalmente la
map()
usaré como lo sugiere @dinodsaurus.fuente
Dependiendo de si tiene Underscore o Babel, aquí hay un Benchmark de la forma diferente de clonar profundamente una matriz.
https://jsperf.com/object-rest-spread-vs-clone/2
Parece que Babel es el más rápido.
fuente
fuente