So I'm always looking for a way to use vanilla JS whenever possible these days, and I discovered that deep copying an object in JavaScript is still weird.
StackOverflow reminded me of the JSON.parse( JSON.stringify( obj ) ) trick, and it looks like Object.assign still doesn't copy nested objects.
jQuery's $.extend() works. But that's not vanilla JS any more.
What hacks do you guys use for copying JS objects?
¯\_(ツ)_/¯

Oldest comments (18)
Well I suppose it depends on how deep the objects are and whether you have control over the organization of the objects. I believe for simple scenarios, you could do something along the following. Dunno if you qualify ES6 as Vanilla JS, so here's some ES5:
The output to the console:
Alternatively, if you have to handle dynamic objects of unknown dimensions, you could use a recursive function that uses Object.getOwnPropertyNames and the prototypes (someObject.__proto__) of those properties to handle the generation of fresh Objects for the properties of the destination object.
Hope that answers your question!
Edit: Added console output for the above script.
That does indeed look like a good solution if you know the object props.
But
JSON.parse( JSON.stringify( obj ) );, though hacky, is much quicker to write!Oh okay. I misunderstood, I thought you were avoiding using that
JSON.parse( JSON.stringify( obj ) );for some reason. Whoops!Have a good Turkey day, or a good Thursday.
So you're saying
Object.assign({}, obj);doesn't work?It does work, but not for nested objects. i.e.:
Yeah it doesn't work on nested objects.
I would use lodash and its assignIn method. I haven't tried yet
Object.assign()so I don't know if it copies nested object and references.Good ol'
var copy = {}; for (var item in obj) { obj.hasOwnProperty(item) && (copy[item] = obj[item]); }approach works most of the times.About those cases when this doesn't work: maybe you're solving the wrong problem.
In plain javascript, there is only one option.
I don't know how and why, but in some cases Object.assign is working, but it's not recommended for use without deep understanding of it.
This is great for simple object literals. But, if someone out there tries it and it doesn't work, allow me to offer some reasons why.
JSON.parsewill fail for any object that recurses on itself. Try this in your console:var a = {}; a.a = a; JSON.stringify(a);. This is uncommon in app-level code, but happens a lot in DOM parsing libraries and frameworks.toJSON()method will be invoked and its response will be assumed to be correct JSON, whether or not it corresponds to the actual properties of the object.To cover your own butt, you're better off doing as others have suggested and using jQuery or Lodash. In modern ES6 code, you don't have to worry about code bloat, since you can just
importthe method you want to use from either toolkit and the rest of the library won't get included in your browser bundle.Normally I would use
lodash'sclone()orcloneDeep()to do that, if I have it into the project already, otherwise the good oldJSON.parse( JSON.stringify( obj ) );is always a great option.Good to see I'm not crazy!
JSON.parse( JSON.stringify( obj ) );seems to be a common 'shortcut'. But assigning each prop to a new object withobj.hasOwnProperty(item)also looks like a good option if you know which properties to look for.I use spread to copy and assign a new value to the old object
but this is the same as
Object.assign({}, obj);, is not a deep copy.I'm all in for vanilla JS but to a point, I would suggest copy the function from Lodash or jQuery. Use the code that was written and tested over the years, circular references can be a pain in the ..code.
I would simply use recursion for a deep copy: