without objetos objects clonar array javascript clone

javascript - objetos - object.assign array



¿Cómo puedo clonar correctamente un objeto JavaScript? (30)

Una forma elegante de clonar un objeto Javascript en una línea de código

Un método Object.assign es parte del estándar ECMAScript 2015 (ES6) y hace exactamente lo que necesita.

var clone = Object.assign({}, obj);

El método Object.assign () se utiliza para copiar los valores de todas las propiedades propias enumerables de uno o más objetos de origen a un objeto de destino.

Lee mas...

El polyfill para soportar navegadores más antiguos:

if (!Object.assign) { Object.defineProperty(Object, ''assign'', { enumerable: false, configurable: true, writable: true, value: function(target) { ''use strict''; if (target === undefined || target === null) { throw new TypeError(''Cannot convert first argument to object''); } var to = Object(target); for (var i = 1; i < arguments.length; i++) { var nextSource = arguments[i]; if (nextSource === undefined || nextSource === null) { continue; } nextSource = Object(nextSource); var keysArray = Object.keys(nextSource); for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { var nextKey = keysArray[nextIndex]; var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey); if (desc !== undefined && desc.enumerable) { to[nextKey] = nextSource[nextKey]; } } } return to; } }); }

Tengo un objeto, x . Me gustaría copiarlo como objeto y , de modo que los cambios en y no modifiquen x . Me di cuenta de que copiar objetos derivados de objetos JavaScript incorporados resultará en propiedades adicionales no deseadas. Esto no es un problema, ya que estoy copiando uno de mis propios objetos construidos literalmente.

¿Cómo puedo clonar correctamente un objeto JavaScript?


Con jQuery, puedes copiar con poca extend :

var copiedObject = jQuery.extend({}, originalObject)

los cambios posteriores al objeto copiado no afectarán al objeto original, y viceversa.

O para hacer una copia profunda :

var copiedObject = jQuery.extend(true, {}, originalObject)


De este artículo: Cómo copiar matrices y objetos en Javascript por Brian Huisman:

Object.prototype.clone = function() { var newObj = (this instanceof Array) ? [] : {}; for (var i in this) { if (i == ''clone'') continue; if (this[i] && typeof this[i] == "object") { newObj[i] = this[i].clone(); } else newObj[i] = this[i] } return newObj; };


En ECMAScript 6 hay Object.assign método Object.assign , que copia los valores de todas las propiedades propias enumerables de un objeto a otro. Por ejemplo:

var x = {myProp: "value"}; var y = Object.assign({}, x);

Pero tenga en cuenta que los objetos anidados todavía se copian como referencia.



Hacer esto para cualquier objeto en JavaScript no será sencillo ni directo. Se encontrará con el problema de recoger erróneamente los atributos del prototipo del objeto que se debe dejar en el prototipo y no se debe copiar en la nueva instancia. Si, por ejemplo, está agregando un método de clone a Object.prototype , como muestran algunas respuestas, deberá omitir explícitamente ese atributo. ¿Pero qué Object.prototype si hay otros métodos adicionales agregados al Object.prototype u otros prototipos intermedios que no conoce? En ese caso, copiará los atributos que no debería, por lo que necesita detectar atributos no locales imprevistos con el método hasOwnProperty .

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, se hace referencia al prototipo de un objeto con el atributo __proto__ , que también está oculto, y no será copiado por un bucle for / in que recorre los atributos del objeto de origen. Creo que __proto__ puede ser específico para el intérprete de JavaScript de Firefox y puede ser algo diferente en otros navegadores, pero te das cuenta. No todo es enumerable. Puede copiar un atributo oculto si conoce su nombre, pero no conozco ninguna forma de descubrirlo automáticamente.

Otro problema en la búsqueda de una solución elegante es el problema de configurar correctamente la herencia del prototipo. Si el prototipo de su objeto fuente es Object , entonces simplemente creará un nuevo objeto general con {} , pero si el prototipo de la fuente es algo descendiente de Object , entonces le faltarán los miembros adicionales de ese prototipo que omitió usando el hasOwnProperty filtro hasOwnProperty , o que estaban en el prototipo, pero no eran enumerables en primer lugar. Una solución podría ser llamar a la propiedad del constructor del objeto de origen para obtener el objeto de copia inicial y luego copiar sobre los atributos, pero aún así no obtendrá atributos no enumerables. Por ejemplo, un objeto Date almacena sus datos como un miembro oculto:

function clone(obj) { if (null == obj || "object" != typeof obj) return obj; var copy = obj.constructor(); for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr]; } return copy; } var d1 = new Date(); /* Executes function after 5 seconds. */ setTimeout(function(){ var d2 = clone(d1); alert("d1 = " + d1.toString() + "/nd2 = " + d2.toString()); }, 5000);

La cadena de fecha para d1 estará 5 segundos detrás de la de d2 . Una forma de hacer que una Date igual a otra es llamando al método setTime , pero eso es específico de la clase Date . No creo que exista una solución general a prueba de balas para este problema, ¡aunque me encantaría estar equivocado!

Cuando tuve que implementar una copia profunda en general, terminé comprometiéndome al asumir que solo tendría que copiar un Object simple, una Array , una Date , una String , un Number o un valor Boolean . Los últimos 3 tipos son inmutables, por lo que podría realizar una copia superficial y no preocuparme por el cambio. Además, asumí que cualquier elemento contenido en Object o Array también sería uno de los 6 tipos simples en esa lista. Esto se puede lograr con código como el siguiente:

function clone(obj) { var copy; // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date if (obj instanceof Date) { copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = clone(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn''t supported."); }

La función anterior funcionará adecuadamente para los 6 tipos simples que mencioné, siempre que los datos en los objetos y matrices formen una estructura de árbol. Es decir, no hay más de una referencia a los mismos datos en el objeto. Por ejemplo:

// This would be cloneable: var tree = { "left" : { "left" : null, "right" : null, "data" : 3 }, "right" : null, "data" : 8 }; // This would kind-of work, but you would get 2 copies of the // inner node instead of 2 references to the same copy var directedAcylicGraph = { "left" : { "left" : null, "right" : null, "data" : 3 }, "data" : 8 }; directedAcyclicGraph["right"] = directedAcyclicGraph["left"]; // Cloning this would cause a due to infinite recursion: var cyclicGraph = { "left" : { "left" : null, "right" : null, "data" : 3 }, "data" : 8 }; cyclicGraph["right"] = cyclicGraph;

No podrá manejar ningún objeto de JavaScript, pero puede ser suficiente para muchos propósitos, siempre y cuando no asuma que solo funcionará para cualquier cosa que le lance.


Hay muchas respuestas, pero ninguna de las cuales menciona Object.create de ECMAScript 5, que no admite 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:

  1. Donde tal herencia es útil (duh!)
  2. Donde el objeto de origen no se modificará, lo que hace que la relación entre los 2 objetos no sea un problema.

Ejemplo:

var foo = { a : 1 }; var bar = Object.create(foo); foo.a; // 1 bar.a; // 1 foo.a = 2; bar.a; // 2 - prototype changed bar.a = 3; foo.a; // Still 2, since setting bar.a makes it an "own" property

¿Por qué considero que esta solución es superior? Es nativo, por lo tanto no hay bucles, no hay recursión. Sin embargo, los navegadores más antiguos necesitarán un polyfill.


Hay 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 debe aceptarse.

situación inicial

Quiero hacer una copia a fondo de un Object Javascript con todos sus hijos y sus hijos, etc. Pero como no soy un desarrollador normal, mi Object tiene properties normales , circular structures e incluso nested objects .

Así que vamos a crear una circular structure y un nested object primero.

function Circ() { this.me = this; } function Nested(y) { this.y = y; }

Vamos a juntar todo en un Object llamado a .

var a = { x: ''a'', circ: new Circ(), nested: new Nested(''a'') };

A continuación, queremos copiar a en una variable llamada b y mutarla.

var b = a; b.x = ''b''; b.nested.y = ''b'';

Sabes lo que sucedió aquí porque, si no, ni siquiera aterrizarías en esta gran pregunta.

console.log(a, b); a --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } }

Ahora encontremos una solución.

JSON

El primer intento que intenté fue usar JSON .

var b = JSON.parse( JSON.stringify( a ) ); b.x = ''b''; b.nested.y = ''b'';

No pierda demasiado tiempo en él, obtendrá TypeError: Converting circular structure to JSON .

Copia recursiva (la "respuesta" aceptada)

Echemos un vistazo a la respuesta aceptada.

function cloneSO(obj) { // Handle the 3 simple types, and null or undefined if (null == obj || "object" != typeof obj) return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0, len = obj.length; i < len; i++) { copy[i] = cloneSO(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { var copy = {}; for (var attr in obj) { if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]); } return copy; } throw new Error("Unable to copy obj! Its type isn''t supported."); }

Se ve bien, ¿eh? Es una copia recursiva del objeto y maneja otros tipos también, como Date , pero eso no era un requisito.

var b = cloneSO(a); b.x = ''b''; b.nested.y = ''b'';

La recursión y circular structures no funcionan bien juntas ... 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 .

var b = Object.create(a); b.x = ''b''; b.nested.y = ''b'';

Esta solución se agregó a Javascript hace algún tiempo e incluso maneja la circular structure .

console.log(a, b); a --> Object { x: "a", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> Object { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } }

... y ves, no funcionó con la estructura anidada dentro.

Poli-relleno para la solución nativa.

Hay un polyfill para Object.create en el navegador antiguo al igual que el IE 8. Es algo como lo recomendado por Mozilla, y por supuesto, no es perfecto y da como resultado el mismo problema que la solución nativa .

function F() {}; function clonePF(o) { F.prototype = o; return new F(); } var b = clonePF(a); b.x = ''b''; b.nested.y = ''b'';

He puesto F fuera del alcance para que podamos echar un vistazo a lo que instanceof nos dice.

console.log(a, b); a --> Object { x: "a", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } b --> F { x: "b", circ: Circ { me: Circ { ... } }, nested: Nested { y: "b" } } console.log(typeof a, typeof b); a --> object b --> object console.log(a instanceof Object, b instanceof Object); a --> true b --> true console.log(a instanceof F, b instanceof F); a --> false b --> true

El mismo problema que la solución nativa , pero un poco peor de salida.

La mejor (pero no perfecta) solución.

Al excavar, encontré una pregunta similar ( en Javascript, al realizar una copia en profundidad, ¿cómo evito un ciclo, debido a que una propiedad es "esta"? ) A esta, pero con una solución mucho mejor.

function cloneDR(o) { const gdcc = "__getDeepCircularCopy__"; if (o !== Object(o)) { return o; // primitive value } var set = gdcc in o, cache = o[gdcc], result; if (set && typeof cache == "function") { return cache(); } // else o[gdcc] = function() { return result; }; // overwrite if (o instanceof Array) { result = []; for (var i=0; i<o.length; i++) { result[i] = cloneDR(o[i]); } } else { result = {}; for (var prop in o) if (prop != gdcc) result[prop] = cloneDR(o[prop]); else if (set) result[prop] = cloneDR(cache); } if (set) { o[gdcc] = cache; // reset } else { delete o[gdcc]; // unset again } return result; } var b = cloneDR(a); b.x = ''b''; b.nested.y = ''b'';

Y echemos un vistazo a la salida ...

console.log(a, b); a --> Object { x: "a", circ: Object { me: Object { ... } }, nested: Object { y: "a" } } b --> Object { x: "b", circ: Object { me: Object { ... } }, nested: Object { y: "b" } } console.log(typeof a, typeof b); a --> object b --> object console.log(a instanceof Object, b instanceof Object); a --> true b --> true console.log(a instanceof F, b instanceof F); a --> false b --> false

Los requisitos coinciden, pero todavía hay algunos problemas menores, incluido el cambio de la instance de nested y circ a Object .

La estructura de los árboles que comparten una hoja no se copiará, se convertirán en dos hojas independientes:

[Object] [Object] / / / / / / / / |/_ _/| |/_ _/| [Object] [Object] ===> [Object] [Object] / / | | / / | | _/| |/_ /|/ /|/ [Object] [Object] [Object]

conclusión

La última solución que utiliza recursión y un caché puede no ser la mejor, pero es una copia profunda del objeto. Maneja properties simples, circular structures y nested object , pero desordenará la instancia de ellos durante la clonación.

jsfiddle


La respuesta de A.Levy está casi completa, aquí está mi pequeña contribución: hay una manera de manejar las referencias recursivas , vea esta línea

if(this[attr]==this) copy[attr] = copy;

Si el objeto es un elemento XML DOM, debemos usar cloneNode en su lugar

if(this.cloneNode) return this.cloneNode(true);

Inspirado por el estudio exhaustivo de A.Levy y el enfoque de creación de prototipos de Calvin, ofrezco esta solución:

Object.prototype.clone = function() { if(this.cloneNode) return this.cloneNode(true); var copy = this instanceof Array ? [] : {}; for(var attr in this) { if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone) copy[attr] = this[attr]; else if(this[attr]==this) copy[attr] = copy; else copy[attr] = this[attr].clone(); } return copy; } Date.prototype.clone = function() { var copy = new Date(); copy.setTime(this.getTime()); return copy; } Number.prototype.clone = Boolean.prototype.clone = String.prototype.clone = function() { return this; }

Véase también la nota de Andy Burke en las respuestas.


Para aquellos que usan AngularJS, también hay un método directo para clonar o extender los objetos en esta biblioteca.

var destination = angular.copy(source);

o

angular.copy(source, destination);

Más en documentation angular.copy ...


Por MDN :

  • Si desea una copia superficial, use Object.assign({}, a)
  • Para una copia "profunda", use JSON.parse(JSON.stringify(a))

No hay necesidad de bibliotecas externas, pero primero debe verificar la compatibilidad del navegador .


Si está de acuerdo con una copia superficial, la biblioteca underscore.js tiene un método de clone .

y = _.clone(x);

o puedes extenderlo como

copiedObject = _.extend({},originalObject);


Si no usa funciones dentro de su objeto, una simple línea puede ser la siguiente:

var cloneOfA = JSON.parse(JSON.stringify(a));

Esto funciona para todo tipo de objetos que contienen objetos, matrices, cadenas, valores booleanos y números.

Consulte también este artículo sobre el algoritmo de clonación estructurada de los navegadores que se utiliza al publicar mensajes hacia y desde un trabajador. También contiene una función para la clonación profunda.


Simplemente puede usar una propiedad de propagación para copiar un objeto sin referencias. Pero tenga cuidado (vea los comentarios), la ''copia'' está solo en el nivel más bajo de objeto / matriz. Las propiedades anidadas siguen siendo referencias!

Clon completo

let x = {a: ''value1''} let x2 = {...x} // => mutate without references: x2.a = ''value2'' console.log(x.a) // => ''value1''

Clon con referencias en segundo nivel:

const y = {a: {b: ''value3''}} const y2 = {...y} // => nested object is still a references: y2.a.b = ''value4'' console.log(y.a.b) // => ''value4''

JavaScript en realidad no admite clones profundos de forma nativa. Utilice una función de utilidad. Por ejemplo Ramda:

http://ramdajs.com/docs/#clone


Una solución especialmente poco inteligente es usar la codificación JSON para hacer copias en profundidad de objetos que no tienen métodos de miembro. La metodología es JSON codificar 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 miembros.

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 contiene una copia del estado original del objeto, por lo que puede calcular el delta después de que el llamante haya mutado el objeto expuesto.

var object1 = {key:"value"}; var object2 = object1; object2 = JSON.stringify(object1); object2 = JSON.parse(object2); object2.key = "a change"; console.log(object1);// returns value


OK, imagina que tienes este objeto debajo y quieres clonarlo:

let obj = {a:1, b:2, c:3}; //ES6

o

var obj = {a:1, b:2, c:3}; //ES5

La respuesta depende principalmente de qué ECMAscript esté utilizando, en ES6+ , simplemente puede usar Object.assign para hacer el clon:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

o utilizando el operador de propagación de esta manera:

let cloned = {...obj}; //new {a:1, b:2, c:3};

Pero si usa ES5 , puede usar algunos métodos, pero JSON.stringify , solo asegúrese de no usar una gran parte de los datos para copiar, pero podría ser una línea útil en muchos casos, algo como esto:

let cloned = JSON.parse(JSON.stringify(obj)); //new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over


Aquí hay una función que puedes usar.

function clone(obj) { if(obj == null || typeof(obj) != ''object'') return obj; var temp = new obj.constructor(); for(var key in obj) temp[key] = clone(obj[key]); return temp; }


En ECMAScript 2018

let objClone = { ...obj };

Tenga en cuenta que los objetos anidados todavía se copian como referencia.



Utilizando Lodash:

var y = _.clone(x, true);


¡Nueva respuesta a una vieja pregunta! Si tiene el placer de utilizar ECMAScript 2016 (ES6) con Spta Syntax , es fácil.

keepMeTheSame = {first: "Me!", second: "You!"}; cloned = {...keepMeTheSame}

Esto proporciona un método limpio para una copia superficial de un objeto. Hacer una copia profunda, lo que significa crear una nueva copia de cada valor en cada objeto anidado recursivamente, requiere una de las soluciones más pesadas de arriba.

JavaScript sigue evolucionando.


Consulte http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data para el algoritmo de "Transferencia segura de datos estructurados" del W3C, que se pretende implementar. por los navegadores para pasar datos a, por ejemplo, los trabajadores web. Sin embargo, tiene algunas limitaciones, ya que no maneja funciones. Consulte https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm para obtener más información, incluido un algoritmo alternativo en JS que lo lleva a una parte del camino.


Dado que mindeavor declaró que el objeto 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:

function createMyObject() { var myObject = { ... }; return myObject; } var myObjectInstance1 = createMyObject(); var myObjectInstance2 = createMyObject();


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 clonan son referencias del mismo objeto, el árbol de objetos clonados tendrá estas Las propiedades apuntan a un mismo clon del objeto al que se hace referencia. Esto también resuelve el caso de dependencias cíclicas que, si no se manejan, conducen a un bucle infinito. La complejidad del algoritmo es O (n).

function clone(obj){ var clonedObjectsArray = []; var originalObjectsArray = []; //used to remove the unique ids when finished var next_objid = 0; function objectId(obj) { if (obj == null) return null; if (obj.__obj_id == undefined){ obj.__obj_id = next_objid++; originalObjectsArray[obj.__obj_id] = obj; } return obj.__obj_id; } function cloneRecursive(obj) { if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj; // Handle Date if (obj instanceof Date) { var copy = new Date(); copy.setTime(obj.getTime()); return copy; } // Handle Array if (obj instanceof Array) { var copy = []; for (var i = 0; i < obj.length; ++i) { copy[i] = cloneRecursive(obj[i]); } return copy; } // Handle Object if (obj instanceof Object) { if (clonedObjectsArray[objectId(obj)] != undefined) return clonedObjectsArray[objectId(obj)]; var copy; if (obj instanceof Function)//Handle Function copy = function(){return obj.apply(this, arguments);}; else copy = {}; clonedObjectsArray[objectId(obj)] = copy; for (var attr in obj) if (attr != "__obj_id" && obj.hasOwnProperty(attr)) copy[attr] = cloneRecursive(obj[attr]); return copy; } throw new Error("Unable to copy obj! Its type isn''t supported."); } var cloneObj = cloneRecursive(obj); //remove the unique ids for (var i = 0; i < originalObjectsArray.length; i++) { delete originalObjectsArray[i].__obj_id; }; return cloneObj; }

Algunas pruebas rápidas

var auxobj = { prop1 : "prop1 aux val", prop2 : ["prop2 item1", "prop2 item2"] }; var obj = new Object(); obj.prop1 = "prop1_value"; obj.prop2 = [auxobj, auxobj, "some extra val", undefined]; obj.nr = 3465; obj.bool = true; obj.f1 = function (){ this.prop1 = "prop1 val changed by f1"; }; objclone = clone(obj); //some tests i''ve made console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool)); objclone.f1(); console.log("test function cloning 1: " + (objclone.prop1 == ''prop1 val changed by f1'')); objclone.f1.prop = ''some prop''; console.log("test function cloning 2: " + (obj.f1.prop == undefined)); objclone.prop2[0].prop1 = "prop1 aux val NEW"; console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1)); console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));


He escrito mi propia implementación. No estoy seguro si cuenta como una mejor solución:

/* a function for deep cloning objects that contains other nested objects and circular structures. objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object. index (z) | | | | | | depth (x) |_ _ _ _ _ _ _ _ _ _ _ _ /_/_/_/_/_/_/_/_/_/ /_/_/_/_/_/_/_/_/_/ /_/_/_/_/_/_/...../ /................./ /..... / / / /------------------ object length (y) / */

La siguiente es la implementación:

function deepClone(obj) { var depth = -1; var arr = []; return clone(obj, arr, depth); } /** * * @param obj source object * @param arr 3D array to store the references to objects * @param depth depth of the current object relative to the passed ''obj'' * @returns {*} */ function clone(obj, arr, depth){ if (typeof obj !== "object") { return obj; } var length = Object.keys(obj).length; // native method to get the number of properties in ''obj'' var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object if(result instanceof Array){ result.length = length; } depth++; // depth is increased because we entered an object here arr[depth] = []; // this is the x-axis, each index here is the depth arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props) // start the depth at current and go down, cyclic structures won''t form on depths more than the current one for(var x = depth; x >= 0; x--){ // loop only if the array at this depth and length already have elements if(arr[x][length]){ for(var index = 0; index < arr[x][length].length; index++){ if(obj === arr[x][length][index]){ return obj; } } } } arr[depth][length].push(obj); // store the object in the array at the current depth and length for (var prop in obj) { if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth); } return result; }


La respuesta anterior de Jan Turoň es muy cercana y puede ser la mejor para usar en un navegador debido a problemas de compatibilidad, pero potencialmente causará algunos problemas de enumeración extraños. Por ejemplo, ejecutando:

for ( var i in someArray ) { ... }

Asignará el método clone () a i después de iterar a través de los elementos de la matriz. Aquí hay una adaptación que evita la enumeración y funciona con node.js:

Object.defineProperty( Object.prototype, "clone", { value: function() { if ( this.cloneNode ) { return this.cloneNode( true ); } var copy = this instanceof Array ? [] : {}; for( var attr in this ) { if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone ) { copy[ attr ] = this[ attr ]; } else if ( this[ attr ] == this ) { copy[ attr ] = copy; } else { copy[ attr ] = this[ attr ].clone(); } } return copy; } }); Object.defineProperty( Date.prototype, "clone", { value: function() { var copy = new Date(); copy.setTime( this.getTime() ); return copy; } }); Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } ); Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } ); Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

Esto evita hacer que el método clone () sea enumerable porque defineProperty () por defecto es enumerable a falso.


Puede clonar un objeto y eliminar cualquier referencia de la anterior utilizando una sola línea de código. Simplemente haz:

var obj1 = { text: ''moo1'' }; var obj2 = Object.create(obj1); // Creates a new clone without references obj2.text = ''moo2''; // Only updates obj2''s text property console.log(obj1, obj2); // Outputs: obj1: {text:''moo1''}, obj2: {text:''moo2''}

Para navegadores / motores que actualmente no son compatibles con Object.create, puede usar este polyfill:

// Polyfill Object.create if it does not exist if (!Object.create) { Object.create = function (o) { var F = function () {}; F.prototype = o; return new F(); }; }


Solo quería agregar a todas las Object.createsoluciones en esta publicación, que esto no funciona de la manera deseada con nodejs.

En Firefox el resultado de

var a = {"test":"test"}; var b = Object.create(a); console.log(b);´

es

{test:"test"} .

En nodejs es

{}


function clone(src, deep) { var toString = Object.prototype.toString; if(!src && typeof src != "object"){ //any non-object ( Boolean, String, Number ), null, undefined, NaN return src; } //Honor native/custom clone methods if(src.clone && toString.call(src.clone) == "[object Function]"){ return src.clone(deep); } //DOM Elements if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){ return src.cloneNode(deep); } //Date if(toString.call(src) == "[object Date]"){ return new Date(src.getTime()); } //RegExp if(toString.call(src) == "[object RegExp]"){ return new RegExp(src); } //Function if(toString.call(src) == "[object Function]"){ //Wrap in another method to make sure == is not true; //Note: Huge performance issue due to closures, comment this :) return (function(){ src.apply(this, arguments); }); } var ret, index; //Array if(toString.call(src) == "[object Array]"){ //[].slice(0) would soft clone ret = src.slice(); if(deep){ index = ret.length; while(index--){ ret[index] = clone(ret[index], true); } } } //Object else { ret = src.constructor ? new src.constructor() : {}; for (var prop in src) { ret[prop] = deep ? clone(src[prop], true) : src[prop]; } } return ret; };


let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

Solución ES6 si desea (superficial) clonar una instancia de clase y no solo un objeto de propiedad.