Reputation: 2083
Googling for "javascript clone object" brings some really weird results, some of them are hopelessly outdated and some are just too complex, isn't it as easy as just:
let clone = {...original};
Is there anything wrong with this?
Upvotes: 195
Views: 183731
Reputation: 145
UPDATE: 05/31/2023 a new global function was release that allows DEEP COPY called window.structuredClone()
const person1 = {
address: {
address1: "my address1",
address2: "my address2"
},
age: 23
};
console.log(person1)
const person2 = window.structuredClone(person1)
person2.address.address1 = "my new address1"
person2.address.address2= "my new address2"
person2.age = 40
console.log(person1) // person1 was not changed
Upvotes: 8
Reputation: 587
I found a solution which seems to copy functions as well, correct me if this example is an error.
Attention I have not tested this method with more complex object cases, which, for example, would include methods with this for reference
Take for example the price of a breakfast, I have this price available globally but I would like to adjust it individually for a hotel room
// make an object for a booking option
var opt_resa = { breakfast_val: 900 }
// i define a function for opt_resa :
opt_resa.func = function(){ alert('i am a function'); }
// copy object in modif.opt_resa :
var modif = { opt_resa : {} }
for ( var v in opt_resa ){
modif.opt_resa[v] = opt_resa[v];
}
// test
modif.opt_resa.breakfast_val = 1500;
// old value
console.log( opt_resa.breakfast_val );
// output : 900
// modified value
console.log( modif.opt_resa.breakfast_val );
// output : 1500
// function copied
modif.opt_resa.func();
// this function works
Upvotes: 0
Reputation: 21
structured Clone you can Used this method
function Copy_Object(obj) { return structuredClone(obj); }
Upvotes: 1
Reputation: 933
You can do it like this as well,
let copiedData = JSON.parse(JSON.stringify(data));
Upvotes: 4
Reputation: 3752
EDIT: When this answer was posted, {...obj}
syntax was not available in most browsers. Nowadays, you should be fine using it (unless you need to support 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 }
However, this won't make a deep clone. There is no native way of deep cloning as of yet.
EDIT: As @Mike 'Pomax' Kamermans mentioned in the comments, you can deep clone simple objects (ie. no prototypes, functions or circular references) using JSON.parse(JSON.stringify(input))
Upvotes: 77
Reputation: 6429
This is good for shallow cloning. The object spread is a standard part of ECMAScript 2018.
For deep cloning you'll need a different solution.
const clone = {...original}
to shallow clone
const newobj = {...original, prop: newOne}
to immutably add another prop to the original and store as a new object.
Upvotes: 305
Reputation: 9380
All the methods above do not handle deep cloning of objects where it is nested to n levels. I did not check its performance over others but it is short and simple.
The first example below shows object cloning using Object.assign
which clones just till first level.
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
Using the below approach deep clones object
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
Upvotes: -1
Reputation: 7728
Following on from the answer by @marcel I found some functions were still missing on the cloned object. e.g.
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 || {};
}
});
}
where on MyObject I could clone methodA but methodB was excluded. This occurred because it is missing
enumerable: true
which meant it did not show up in
for(let key in item)
Instead I switched over to
Object.getOwnPropertyNames(item).forEach((key) => {
....
});
which will include non-enumerable keys.
I also found that the prototype (proto) was not cloned. For that I ended up using
if (obj.__proto__) {
copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}
PS: Frustrating that I could not find a built in function to do this.
Upvotes: 2
Reputation: 1167
If the methods you used isn't working well with objects involving data types like Date, try this
Import _
import * as _ from 'lodash';
Deep clone object
myObjCopy = _.cloneDeep(myObj);
Upvotes: 8
Reputation: 113
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.
But Object.assign() not create a deep clone
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
To fix that, we should use the cloning loop that examines each value of user[key] and, if it’s an object, then replicate its structure as well. That is called a “deep cloning”.
There’s a standard algorithm for deep cloning that handles the case above and more complex cases, called the Structured cloning algorithm. In order not to reinvent the wheel, we can use a working implementation of it from the JavaScript library lodash the method is called _.cloneDeep(obj).
Upvotes: 0
Reputation: 3272
if you don't want to use json.parse(json.stringify(object)) you could create recursively key-value copies:
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;
}
But the best way is to create a class that can return a clone of it self
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) }
}
Upvotes: 3