Copia profunda de una matriz de objetos anidados en javascript
arrays deep-copy (1)
Esta pregunta ya tiene una respuesta aquí:
Estoy tratando de copiar en profundidad la matriz de objetos anidados en javascript. Mi matriz se parece a esto
var arr = [{name:"adam",age:"21"},
{name:"freddie",age:"35",children:[{name:"mercury",age:"25"}]},
{name:"jim",age:"35",children:[{name:"morrison",age:"25",children:[{name:"some", age:"40"}]}]}
];
Quiero hacer una copia profunda de cada objeto dentro de la matriz que quiero crear una copia exacta de arr en la nueva matriz que no debería tener referencia de objeto. La profundidad de la matriz también se desconoce, ya que la matriz de los niños puede estar en cualquier nivel. He pasado por este enlace Copia de una matriz de objetos a otra matriz sin referencia de objeto en javascript (Copia profunda) pero eso no me ayudó. Busqué en Google y encontré algunas soluciones en jQuery pero eso no me ayudó porque no tengo conocimiento de jQuery.
También intenté implementarlo con recursión, pero eso no funciona también http://ideone.com/kJi5X3
Quiero hacerlo en javascript solo sin usar jQuery ni nada. Soy nuevo en JavaScript, así que es posible que haya omitido si hay alguna biblioteca o método simple para hacer esto. Por favor ayúdame a resolver este problema. Gracias por adelantado.
Tienes dos opciones principales:
Utilice
JSON.stringify
yJSON.parse
:var copy = JSON.parse(JSON.stringify(original));
Pero nunca me ha gustado eso. Un viaje de ida y vuelta a través del texto es, en el mejor de los casos, ineficiente, y no manejará correctamente los valores de
Date
,RegExp
,undefined
, etc., a menos que escriba un sustituto y un revisor.Usa una función recursiva, algo como esto:
var toString = Object.prototype.toString;
function deepCopy(obj) {
var rv;
switch (typeof obj) {
case "object":
if (obj === null) {
// null => null
rv = null;
} else {
switch (toString.call(obj)) {
case "[object Array]":
// It''s an array, create a new array with
// deep copies of the entries
rv = obj.map(deepCopy);
break;
case "[object Date]":
// Clone the date
rv = new Date(obj);
break;
case "[object RegExp]":
// Clone the RegExp
rv = new RegExp(obj);
break;
// ...probably a few others
default:
// Some other kind of object, deep-copy its
// properties into a new object
rv = Object.keys(obj).reduce(function(prev, key) {
prev[key] = deepCopy(obj[key]);
return prev;
}, {});
break;
}
}
break;
default:
// It''s a primitive, copy via assignment
rv = obj;
break;
}
return rv;
}
var a = [1, {foo: "bar"}, [''a'', ''b''], new Date()];
snippet.log(JSON.stringify(a));
var b = deepCopy(a);
snippet.log(JSON.stringify(b));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Tenga en cuenta que lo anterior utiliza las características de ES5 presentes en todos los navegadores modernos, pero no en algunos más antiguos, como IE8. Sin embargo, todas las funciones utilizadas anteriormente pueden ser rellenadas políticamente para los navegadores más antiguos.
Eso no intenta manejar funciones de constructor personalizadas o preservar prototipos en objetos de la matriz; hacerlo así hace que las cosas sean mucho más complicadas e imposibles de hacer perfectas sin una convención sobre cómo llamar a esos constructores para una operación de copia. Puede acercarse asignando el mismo prototipo, pero eso no tendría en cuenta la lógica dentro de la función del constructor y, en particular, las funciones configuradas como cierres dentro de él.