Reputation: 229
I've been surfing around here a while and still haven't found an answer that worked for me.
Is there any way to deep copy a non-plain object in JS?
I've tried jQuery.extend(true, {}, this)
but it only cloned some of it, the rest remained as a reference to another object.
Upvotes: 12
Views: 28168
Reputation: 21
You could use the structuredClone method:
const cloned = structuredClone(object)
Anyway, structuredClone allows you to do also other things that you might be interested in.
Check the documentation for further details:
https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
Upvotes: 2
Reputation: 4261
A quick method to clone objects deep with performance into consideration.
JSON.parse(JSON.stringify({"foo":"bar"}))
How about performance ? >> [ May be this is the best way to deep copy objects ]. I strongly recommend you to checkout this video from Google Chrome Developers community on Youtube explaining how this method works and performance benchmarks.
Note: Use the
JSON.parse
method if your objects don't have Dates, functions, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays or other complex types. Source : Read this SO answer
Quick tip - React.JS initial state tree can be loaded from localStorage using this solution.
Upvotes: 1
Reputation: 457
Lodash _.cloneDeep() method kills the application performance. So I have come up with basic JavaScript solution. I have added it to my GIT repo. My application performance is back to normal after using my solution.
https://github.com/manideeppabba1991/javascript_util_functions/blob/master/clone_Array_or_Object.js
Upvotes: -1
Reputation: 8058
Here are 3 different methods for copying objects. Each method has pros and cons, so read through and pick the best for your situation
Use Object.assign
, which "is used to copy the values of all enumerable own properties from one or more source objects to a target object". This copies both values and functions. At the time of writing this, browser support is good but not perfect, but this is the best method IMO of the three.
const obj1 = {a:1, b:2};
const obj1Copy = Object.assign(obj1)
Alternatively, you can use the spread operator
to spread from one object into another. Keep in mind that this will copy the values of keys, but if you the value of a key is a memory address (an other nested object or an array) then it will only be a shallow copy.
const obj1 = {a: () => {}, b:2}
const obj1Copy = { ...obj1 }
If the object doesn't have any circular references or functions as values, you can use the json stringify trick:
let myCopy = JSON.parse(JSON.stringify(myObject));
No libraries required, and works very well for most objects.
Upvotes: 13
Reputation: 6282
If you are dealing with a class instance you could use something like this.
You wouldn't need to copy the functions as they are delegated to on the prototype.
// myObject constructor
function myObject(foo, bar){
this.foo = foo
this.bar = bar
}
// delegate the functions to a prototype
myObject.prototype.something = function(){
console.log('something')
}
function instanceCopy(obj) {
// copy the object by the constructor
const copy = new obj.constructor()
const keys = Object.keys(obj)
keys.forEach(key => {
copy[key] = obj[key]
})
return copy
}
const myObj = new myObject('foo', 'bar')
const copyObj = instanceCopy(myObj)
console.log('myObj', myObj)
console.log('copyObj', copyObj)
console.log('same ?', copyObj === myObj)
// can we still call the functions
copyObj.something()
<script src="https://codepen.io/synthet1c/pen/WrQapG.js"></script>
Upvotes: 0
Reputation: 18205
You can use lodash's cloneDeep function - https://lodash.com/docs/4.16.4#cloneDeep
Example (from docs)
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
Upvotes: 5