Cómo hacer una clonación profunda en javascript


105

¿Cómo se clona en profundidad un objeto Javascript?

Sé que hay varias funciones basadas en marcos como JSON.parse(JSON.stringify(o))y, $.extend(true, {}, o)pero no quiero usar un marco como ese.

¿Cuál es la forma más elegante o eficiente de crear un clon profundo?

Nos preocupan los casos extremos como los de clonación de matrices. No romper cadenas de prototipos, ocuparse de la autorreferencia.

No nos importa admitir la copia de objetos DOM y nos gusta porque .cloneNodeexiste por esa razón.

Como principalmente quiero usar clones profundos, el node.jsuso de las características ES5 del motor V8 es aceptable.

[Editar]

Antes de que alguien sugiera, permítanme mencionar que hay una diferencia clara entre crear una copia heredando prototípicamente del objeto y clonarlo . El primero ensucia la cadena del prototipo.

[Edición adicional]

Después de leer su respuesta, llegué al molesto descubrimiento de que clonar objetos enteros es un juego muy peligroso y difícil. Tomemos, por ejemplo, el siguiente objeto basado en cierre

var o = (function() {
     var magic = 42;

     var magicContainer = function() {
          this.get = function() { return magic; };
          this.set = function(i) { magic = i; };
     }

      return new magicContainer;
}());

var n = clone(o); // how to implement clone to support closures

¿Hay alguna forma de escribir una función de clonación que clone el objeto, tenga el mismo estado en el momento de la clonación pero no pueda alterar el estado de osin escribir un analizador JS en JS?

Ya no debería haber necesidad en el mundo real de tal función. Este es un mero interés académico.


2
Antes de que se marque como duplicado, miré stackoverflow.com/questions/122102/… y no encontré ninguna respuesta que se ocupara de todos los casos extremos.
Raynos

El requisito en la sección de "edición adicional" es imposible de lograr sin la "ayuda" del propio objeto, ya que tales variables privadas son verdaderamente privadas y, en consecuencia, no son accesibles por una clonefunción genérica . El objeto en cuestión debe exponer su propio clonemétodo hecho a medida .
trincot

He estado leyendo un montón sobre esto esta noche, y entre los recursos que encontré estaba esta publicación de blog de aspecto feo que incluye un par de trucos para acceder al algoritmo de clonación estructurada en el navegador: dassur.ma/things/deep-copy
Cat

Respuestas:


67

Realmente depende de lo que le gustaría clonar. ¿Es este un verdadero objeto JSON o cualquier objeto en JavaScript? Si desea hacer cualquier clon, podría meterse en problemas. ¿Qué problema? Lo explicaré a continuación, pero primero, un ejemplo de código que clona literales de objetos, cualquier primitiva, matriz y nodos DOM.

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}

var copy = clone({
    one : {
        'one-one' : new String("hello"),
        'one-two' : [
            "one", "two", true, "four"
        ]
    },
    two : document.createElement("div"),
    three : [
        {
            name : "three-one",
            number : new Number("100"),
            obj : new function() {
                this.name = "Object test";
            }   
        }
    ]
})

Y ahora, hablemos de los problemas que podría tener al comenzar a clonar objetos REALES. Estoy hablando ahora de objetos que creas haciendo algo como

var User = function(){}
var newuser = new User();

Por supuesto, puede clonarlos, no es un problema, cada objeto expone la propiedad del constructor y puede usarlo para clonar objetos, pero no siempre funcionará. También puede hacer algo simple for inen estos objetos, pero va en la misma dirección: problemas. También he incluido la funcionalidad de clonación dentro del código, pero está excluida por if( false )declaración.

Entonces, ¿por qué la clonación puede ser un dolor? Bueno, antes que nada, cada objeto / instancia puede tener algún estado. Nunca puede estar seguro de que sus objetos no tienen, por ejemplo, variables privadas, y si este es el caso, al clonar el objeto, simplemente rompe el estado.

Imagina que no hay un estado, está bien. Entonces todavía tenemos otro problema. La clonación mediante el método "constructor" nos dará otro obstáculo. Es una dependencia de argumentos. Nunca puedes estar seguro de que alguien que creó este objeto no lo hizo, algún tipo de

new User({
   bike : someBikeInstance
});

Si este es el caso, no tiene suerte, es probable que someBikeInstance se haya creado en algún contexto y ese contexto no se conoce para el método de clonación.

¿Entonces lo que hay que hacer? Todavía puedes hacerfor in solución y tratar tales objetos como literales de objetos normales, pero tal vez sea una idea no clonar tales objetos en absoluto y simplemente pasar la referencia de este objeto.

Otra solución es: podría establecer una convención de que todos los objetos que deben clonarse deben implementar esta parte por sí mismos y proporcionar el método API adecuado (como cloneObject). Algo que cloneNodeestá haciendo por DOM.

Tú decides.


Me encontré con el obstáculo de lidiar con objetos que usan cierres para ocultar el estado. ¿Cómo se puede clonar un objeto y su estado completo pero aún así asegurarse de que el clon no pueda alterar el estado original por sí mismo? Un punto de couinter para result = new item.constructor();ser malo es que, dada la función del constructor y el objeto del elemento, debería poder RE cualquier parámetro pasado al constructor.
Raynos

7
@Raynos: si los objetos usan cierres para ocultar el estado, entonces no puedes clonarlos. De ahí el término "cierre". Como dice nemisj al final, la mejor manera es implementar un método API para la clonación (o serialización / deserialización) si esa es una opción.
Michiel Kalkman

@MichielKalkman Tenía la sensación de que ese era el caso. Aunque alguien podría haber tenido una solución realmente inteligente para esto.
Raynos

¿Cuál es el efecto de false && item.constructor? ¿No es ifinútil?
Gabriel Petrovay

2
@GabrielPetrovay Eso ifes 'inútil' desde la perspectiva funcional, porque nunca se ejecutará, pero tiene el propósito académico de mostrar una implementación hipotética que uno podría intentar usar, que el autor no aconseja por la razón que se explica más adelante. Entonces, sí, activará una elsecláusula cada vez que se evalúe la condición y, sin embargo, hay una razón para que el código esté allí.
Gui Imamura

154

Manera muy simple, quizás demasiado simple:

var cloned = JSON.parse(JSON.stringify(objectToClone));

12
Genial, a menos que el valor de un objeto sea una función, en ese momento tendrá que usar algo como la respuesta aceptada. O use una función auxiliar como cloneDeepen Lodash.
Matthoiland

31
Si el valor de un objeto es una función, el objeto no es JSON.
Jos de Jong

5
¿Qué caso de uso puede justificar clonar una función en lugar de simplemente usarla?
G. Ghez

3
Si recuerdo correctamente, esto también convierte las fechas en cadenas.
Peter

3
@ G.Ghez si clona un objeto que contiene una función, esa función se perderá ..
Peter

38

La JSON.parse(JSON.stringify())combinación para copiar objetos Javascript en profundidad es un truco ineficaz, ya que estaba destinado a datos JSON. No admite valores de undefinedo function () {}, y simplemente los ignorará (o nullellos) cuando "cadena" (ordena) el objeto Javascript en JSON.

Una mejor solución es utilizar una función de copia profunda. La función a continuación copia en profundidad los objetos y no requiere una biblioteca de terceros (jQuery, LoDash, etc.).

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

7
Excepto cuando unObjeto (u otro objeto que contiene) contiene una autorreferencia a sí mismo ... ¡stackoverflow ™!
e2-e4

@ ringø - ¿Puede proporcionar algunos casos de prueba de "autorreferencia"?
tfmontague

4
var o = { a:1, b:2 } ; o["oo"] = { c:3, m:o };
e2-e4

4
Me gusta esta solucion La única solución para mí fue lidiar con valores nulos: bObject[k] = (v === null) ? null : (typeof v === "object") ? copy(v) : v;
David Kirkland

2
Esta función es simple, comprensible y detectará casi todos los casos. En el mundo de JavaScript, eso es lo más perfecto que puedes conseguir.
icc97

21

Aquí hay una función ES6 que también funcionará para objetos con referencias cíclicas:

function deepClone(obj, hash = new WeakMap()) {
    if (Object(obj) !== obj) return obj; // primitives
    if (hash.has(obj)) return hash.get(obj); // cyclic reference
    const result = obj instanceof Set ? new Set(obj) // See note about this!
                 : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => 
                                        [key, deepClone(val, hash)])) 
                 : obj instanceof Date ? new Date(obj)
                 : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
                 // ... add here any specific treatment for other classes ...
                 // and finally a catch-all:
                 : obj.constructor ? new obj.constructor() 
                 : Object.create(null);
    hash.set(obj, result);
    return Object.assign(result, ...Object.keys(obj).map(
        key => ({ [key]: deepClone(obj[key], hash) }) ));
}

// Sample data
var p = {
  data: 1,
  children: [{
    data: 2,
    parent: null
  }]
};
p.children[0].parent = p;

var q = deepClone(p);

console.log(q.children[0].parent.data); // 1

Una nota sobre conjuntos y mapas

Cómo manejar las claves de Conjuntos y Mapas es discutible: esas claves son a menudo primitivas (en cuyo caso no hay debate), pero también pueden ser objetos. En ese caso, la pregunta es: ¿deben clonarse esas claves?

Se podría argumentar que esto debería hacerse, de modo que si esos objetos se mutan en la copia, los objetos en el original no se vean afectados, y viceversa.

Por otro lado, uno querría que si un Establecer / Mapear hasuna clave, esto sea cierto tanto en el original como en la copia, al menos antes de que se realice cualquier cambio en cualquiera de ellos. Sería extraño si la copia fuera un Set / Map que tenga claves que nunca antes se produjeron (ya que fueron creadas durante el proceso de clonación): seguramente eso no es muy útil para cualquier código que necesite saber si un objeto dado es un introduzca ese Conjunto / Mapa o no.

Como notará, soy más de la segunda opinión: las claves de Conjuntos y Mapas son valores (tal vez referencias ) que deberían permanecer iguales.

Estas elecciones a menudo también aparecerán con otros objetos (tal vez personalizados). No existe una solución general, ya que mucho depende de cómo se espera que se comporte el objeto clonado en su caso específico.


no maneja fecha y
expresión regular

1
@mkeremguc, gracias por tu comentario. Actualicé el código para admitir fecha y expresión regular.
Trincot

Buena solución que incluye mapa. Solo falta soporte para clonar conjuntos es6.
Robert Biggs

Si no me equivoco, probablemente pueda agregar soporte para Sets con:if (object instanceof Set) Array.from(object, val => result.add(deepClone(val, hash)));
Robert Biggs

@RobertBiggs, esa es una posibilidad, pero en mi opinión, si un conjunto tiene una determinada clave, eso también debería ser cierto en la versión clonada de ese conjunto. Con su código sugerido, esto no sería cierto si las claves son objetos. Por lo tanto, sugeriría no clonar las claves; realmente creo que se comportaría más como se esperaba. Vea la actualización de mi respuesta a ese respecto.
trincot

10

La biblioteca de la biblioteca contrib de Underscore.js tiene una función llamada instantánea que clona en profundidad un objeto

fragmento de la fuente:

snapshot: function(obj) {
  if(obj == null || typeof(obj) != 'object') {
    return obj;
  }

  var temp = new obj.constructor();

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) {
      temp[key] = _.snapshot(obj[key]);
    }
  }

  return temp;
}

una vez que la biblioteca esté vinculada a su proyecto, invoque la función simplemente usando

_.snapshot(object);

4
buena solución, solo un punto para recordar: el clon y el original comparten el mismo prototipo. si eso es un problema, es posible agregar "temp .__ proto__ = .snapshot (obj .__ proto_ );" justo encima de "return temp", y para admitir clases integradas con propiedades marcadas como 'no enumerate', puede iterar en getOwnPropertyNames () en lugar de "for (var key in obj)"
Ronen Ness

3

Este es el método de clonación profunda que utilizo, lo creo genial, espero que hagas sugerencias

function deepClone (obj) {
    var _out = new obj.constructor;

    var getType = function (n) {
        return Object.prototype.toString.call(n).slice(8, -1);
    }

    for (var _key in obj) {
        if (obj.hasOwnProperty(_key)) {
            _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
        }
    }
    return _out;
}

3

Como otros han señalado sobre esta y otras cuestiones similares, la clonación de un "objeto", en el sentido general, es dudosa en JavaScript.

Sin embargo, hay una clase de objetos, a los que llamo objetos de "datos", es decir, aquellos construidos simplemente a partir de { ... }literales y / o asignaciones de propiedades simples o deserializados de JSON para los que es razonable querer clonar. Hoy mismo quería inflar artificialmente los datos recibidos de un servidor en 5x para probar lo que sucede para un conjunto de datos grande, pero el objeto (una matriz) y sus elementos secundarios tenían que ser objetos distintos para que las cosas funcionaran correctamente. La clonación me permitió hacer esto para multiplicar mi conjunto de datos:

return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));

El otro lugar donde a menudo termino clonando objetos de datos es para enviar datos al host donde quiero quitar los campos de estado del objeto en el modelo de datos antes de enviarlo. Por ejemplo, es posible que desee eliminar todos los campos que comienzan con "_" del objeto a medida que se clona.

Este es el código que terminé escribiendo para hacer esto de manera genérica, incluidas las matrices de soporte y un selector para elegir qué miembros clonar (que usa una cadena de "ruta" para determinar el contexto):

function clone(obj,sel) {
    return (obj ? _clone("",obj,sel) : obj);
    }

function _clone(pth,src,sel) {
    var ret=(src instanceof Array ? [] : {});

    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }

        var val=src[key], sub;

        if(sel) {
            sub+=pth+"/"+key;
            if(!sel(sub,key,val)) { continue; }
            }

        if(val && typeof(val)=='object') {
            if     (val instanceof Boolean) { val=Boolean(val);        }
            else if(val instanceof Number ) { val=Number (val);        }
            else if(val instanceof String ) { val=String (val);        }
            else                            { val=_clone(sub,val,sel); }
            }
        ret[key]=val;
        }
    return ret;
    }

La solución de clonación profunda razonable más simple, asumiendo un objeto raíz no nulo y sin selección de miembros es:

function clone(src) {
    var ret=(src instanceof Array ? [] : {});
    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }
        var val=src[key];
        if(val && typeof(val)=='object') { val=clone(val);  }
        ret[key]=val;
        }
    return ret;
    }

2

Lo-Dash , ahora un superconjunto de Underscore.js , tiene un par de funciones de clonación profunda:

De una respuesta del propio autor :

lodash underscore build se proporciona para garantizar la compatibilidad con la última versión estable de Underscore.


la pregunta decía "no quiero usar bibliotecas"
Femi Oni

@FemiOni la pregunta no tiene nada sobre bibliotecas (incluso en sus ediciones anteriores) ... Algunas otras respuestas aquí también están usando una biblioteca u otra.
CPHPython

@FemiOni respondió ayer con una votación negativa. Me pregunto ... De todos modos, este es un lugar de aprendizaje y, en caso de que alguien realmente vaya a implementar el clon profundo, el código fuente de LodashbaseClone puede proporcionar algunas ideas.
CPHPython

@FemiOni, el objeto JSON no es una biblioteca ni un marco ... Si va a implementar la función, le sugiero que busque en una de las bibliotecas de código abierto y use las partes que necesita (muchas se han probado durante años). Evitará errores y consideraciones perdidas a largo plazo.
CPHPython

2

La siguiente función es la forma más eficiente de clonar objetos javascript en profundidad.

function deepCopy(obj){
    if (!obj || typeof obj !== "object") return obj;

    var retObj = {};

    for (var attr in obj){
        var type = obj[attr];

        switch(true){
            case (type instanceof Date):
                var _d = new Date();
                _d.setDate(type.getDate())
                retObj[attr]= _d;
                break;

            case (type instanceof Function):
                retObj[attr]= obj[attr];
                break;

            case (type instanceof Array):
                var _a =[];
                for (var e of type){
                    //_a.push(e);
                    _a.push(deepCopy(e));
                }
                retObj[attr]= _a;
                break;

            case (type instanceof Object):
                var _o ={};
                for (var e in type){
                    //_o[e] = type[e];
                    _o[e] = deepCopy(type[e]);
                }
                retObj[attr]= _o;
                break;

            default:
                retObj[attr]= obj[attr];
        }
    }
    return retObj;
}

var obj = {
    string: 'test',
    array: ['1'],
    date: new Date(),
    object:{c: 2, d:{e: 3}},
    function: function(){
        return this.date;
    }
};

var copyObj = deepCopy(obj);

console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true

2
¿Tiene algún argumento para respaldar su afirmación?
Fabian von Ellerts

He dado un ejemplo debajo de la función. ¿Tienes alguna duda?
Kooldandy

Esos ejemplos muestran que la función está funcionando, lo cual es genial, pero ¿por qué es "la forma más eficiente"?
Fabian von Ellerts

Porque está copiando recursivamente los atributos del objeto en un solo bucle. Además, la fecha, la función, el objeto, la matriz, el número, la cadena se manejan correctamente. ¿Tienes alguna otra forma de evitarlo?
Kooldandy

2

Ya no debería haber necesidad en el mundo real de tal función. Este es un mero interés académico.

Como meramente un ejercicio, esta es una forma más funcional de hacerlo. Es una extensión de la respuesta de @ tfmontague, ya que sugerí agregar un bloque de guardia allí. Pero como me siento obligado a ES6 y funcionalizo todas las cosas, aquí está mi versión proxeneta. Complica la lógica, ya que debe mapear la matriz y reducir el objeto, pero evita cualquier mutación.

const cloner = (x) => {
    const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
    const cloneObj = (y, k) => {
        y[k] = recurseObj(x[k])
        return y
    }
    // Guard blocks
    // Add extra for Date / RegExp if you want
    if (!x) {
        return x
    }
    if (Array.isArray(x)) {
        return x.map(recurseObj)
    }
    return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
    null,
    [],
    {},
    [1,2,3],
    [1,2,3, null],
    [1,2,3, null, {}],
    [new Date('2001-01-01')], // FAIL doesn't work with Date
    {x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
    {
        obj : new function() {
            this.name = "Object test";
        }
    } // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))


1

Noté que Map debería requerir un tratamiento especial, por lo tanto, con todas las sugerencias en este hilo, el código será:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

1

mi adición a todas las respuestas

deepCopy = arr => {
  if (typeof arr !== 'object') return arr
  if(arr.pop) return [...arr].map(deepCopy)
  const copy = {}
  for (let prop in arr)
    copy[prop] = deepCopy(arr[prop])
  return copy
}

0

Esto funciona para matrices, objetos y primitivas. Algoritmo doblemente recursivo que cambia entre dos métodos transversales:

const deepClone = (objOrArray) => {

  const copyArray = (arr) => {
    let arrayResult = [];
    arr.forEach(el => {
        arrayResult.push(cloneObjOrArray(el));
    });
    return arrayResult;
  }

  const copyObj = (obj) => {
    let objResult = {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        objResult[key] = cloneObjOrArray(obj[key]);
      }
    }
    return objResult;
  }

  const cloneObjOrArray = (el) => {
    if (Array.isArray(el)) {
      return copyArray(el);
    } else if (typeof el === 'object') {
      return copyObj(el);
    } else {
      return el;
    }
  }

  return cloneObjOrArray(objOrArray);
}

0

Podemos utilizar la recursividad para hacer deepCopy. Puede crear una copia de matriz, objeto, matriz de objeto, objeto con función. si lo desea, puede agregar funciones para otro tipo de estructura de datos como mapa, etc.

function deepClone(obj) {
         var retObj;
        _assignProps = function(obj, keyIndex, retObj) {
               var subType = Object.prototype.toString.call(obj[keyIndex]);
               if(subType === "[object Object]" || subType === "[object Array]") {
                    retObj[keyIndex] = deepClone(obj[keyIndex]);
               }
               else {
                     retObj[keyIndex] = obj[keyIndex];
               }
        };

        if(Object.prototype.toString.call(obj) === "[object Object]") {
           retObj = {};
           for(key in obj) {
               this._assignProps(obj, key, retObj);
           }
        }
        else if(Object.prototype.toString.call(obj) == "[object Array]") {
           retObj = [];
           for(var i = 0; i< obj.length; i++) {
              this._assignProps(obj, i, retObj);
            }
        };

        return retObj;
    };

0

Utilice immutableJS

import { fromJS } from 'immutable';

// An object we want to clone
let objA = { 
   a: { deep: 'value1', moreDeep: {key: 'value2'} } 
};

let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object

console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }

// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false

O lodash / fusionar

import merge from 'lodash/merge'

var objA = {
    a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA ); 

// We can also create new object from several objects by deep merge:
var objB = {
    a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

0

Este, usando una referencia circular, funciona para mí.

 //a test-object with circular reference :
 var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
 var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
 var o = { arr:[n1,n2],   parent:undefined } 
 n1.parent = n2.parent = o;
 var obj = {   a:1,   b:2,   o:o }
 o.parent = obj;

 function deepClone(o,output){ 

     if(!output) output = {};  
     if(o.______clone) return o.______clone;
     o.______clone = output.______clone = output;

   for(var z in o){

     var obj = o[z];
     if(typeof(obj) == "object") output[z] = deepClone(obj)
     else output[z] = obj; 
    }

   return output;
}

console.log(deepClone(obj));

0

var newDate = nueva fecha (this.oldDate); Estaba pasando oldDate para funcionar y generando newDate a partir de this.oldDate, pero también estaba cambiando this.oldDate. Así que usé esa solución y funcionó.


0

Esta solución evitará problemas de recursividad al usar [... target] o {... target}

function shallowClone(target) {
  if (typeof a == 'array') return [...target]
  if (typeof a == 'object') return {...target}
  return target
}

/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
  if (!refs) refs = []
  if (!path) path = ''
  if (refs.indexOf(target) > -1) {
    if (skipRecursion) return null
    throw('Recursive reference at ' + path)
  }
  refs.push(target)
  let clone = shallowCopy(target)
  for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
  return clone
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.