javascript - recorrer - ¿Es esta una buena manera de clonar un objeto en ES6?
recorrer array de objetos javascript (7)
EDITAR: cuando se publicó esta respuesta, la sintaxis
{...obj}
no estaba disponible en la mayoría de los navegadores.
Hoy en día, deberías estar bien usándolo (a menos que necesites soportar IE 11).
Use Object.assign.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
Sin embargo, esto no hará un clon profundo. Todavía no existe una forma nativa de clonación profunda.
EDITAR: Como @Mike ''Pomax'' Kamermans mencionó en los comentarios, puede clonar objetos simples (es decir, sin prototipos, funciones o referencias circulares) usando
JSON.parse(JSON.stringify(input))
Buscar en Google el "objeto de clonación de JavaScript" trae resultados realmente extraños, algunos de ellos están desactualizados y otros son demasiado complejos, ¿no es tan fácil como:
let clone = {...original};
¿Hay algo malo con esto?
Esto es bueno para la clonación superficial . La developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… .
Para una clonación profunda, necesitará una solución diferente .
const clone = {...original}
a clon superficial
const newobj = {...original, prop: newOne}
para agregar de manera inmutable otro accesorio al original y almacenarlo como un nuevo objeto.
Si los métodos que usó no funcionan bien con objetos que involucran tipos de datos como Fecha , intente esto
Importar
_
import * as _ from ''lodash'';
Objeto clon profundo
myObjCopy = _.cloneDeep(myObj);
Siguiendo la respuesta de @marcel, encontré que todavía faltaban algunas funciones en el objeto clonado. p.ej
function MyObject() {
var methodAValue = null,
methodBValue = null
Object.defineProperty(this, "methodA", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
},
enumerable: true
});
Object.defineProperty(this, "methodB", {
get: function() { return methodAValue; },
set: function(value) {
methodAValue = value || {};
}
});
}
donde en MyObject pude clonar el método A pero se excluyó el método B. Esto ocurrió porque falta
enumerable: true
lo que significaba que no apareció en
for(let key in item)
En cambio, cambié a
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
que incluirá claves no enumerables.
También descubrí que el prototipo ( proto ) no estaba clonado. Para eso terminé usando
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PD: Frustrante que no pude encontrar una función integrada para hacer esto.
Todos los métodos anteriores no manejan la clonación profunda de objetos donde está anidada en n niveles. No verifiqué su rendimiento sobre otros, pero es breve y simple.
El primer ejemplo a continuación muestra la clonación de objetos usando
Object.assign
que clona hasta el primer nivel.
var person = {
name:''saksham'',
age:22,
skills: {
lang:''javascript'',
experience:5
}
}
newPerson = Object.assign({},person);
newPerson.skills.lang = ''angular'';
console.log(newPerson.skills.lang); //logs Angular
Usando el siguiente enfoque clones profundos objeto
var person = {
name:''saksham'',
age:22,
skills: {
lang:''javascript'',
experience:5
}
}
anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = ''angular'';
console.log(person.skills.lang); //logs javascript
si no desea usar json.parse (json.stringify (objeto)), puede crear copias recursivamente de valor clave:
function copy(item){
let result = null;
if(!item) return result;
if(Array.isArray(item)){
result = [];
item.forEach(element=>{
result.push(copy(element));
});
}
else if(item instanceof Object && !(item instanceof Function)){
result = {};
for(let key in item){
if(key){
result[key] = copy(item[key]);
}
}
}
return result || item;
}
Pero la mejor manera es crear una clase que pueda devolver un clon de sí mismo
class MyClass{
data = null;
constructor(values){ this.data = values }
toString(){ console.log("MyClass: "+this.data.toString(;) }
remove(id){ this.data = data.filter(d=>d.id!==id) }
clone(){ return new MyClass(this.data) }
}
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating
over its properties and copying them on the primitive level.
let user = {
name: "John",
age: 30
};
let clone = {}; // the new empty object
// let''s copy all user properties into it
for (let key in user) {
clone[key] = user[key];
}
// now clone is a fully independant clone
clone.name = "Pete"; // changed the data in it
alert( user.name ); // still John in the original object
2- Second we can use the method Object.assign for that
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// copies all properties from permissions1 and permissions2 into user
Object.assign(user, permissions1, permissions2);
-Another example
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.
Pero Object.assign () no crea un clon profundo
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true, same object
// user and clone share sizes
user.sizes.width++; // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one
Para solucionarlo, debemos usar el ciclo de clonación que examina cada valor de usuario [clave] y, si es un objeto, replicar también su estructura. Eso se llama una "clonación profunda".
Existe un algoritmo estándar para la clonación profunda que maneja el caso anterior y casos más complejos, llamado algoritmo de clonación estructurada. Para no reinventar la rueda, podemos usar una implementación funcional desde la biblioteca de JavaScript, lodash el método se llama _.cloneDeep(obj) .