Deep Copying JS Objects
On a calc page in a recent project I was working on, I had some default values taken from an object, and I wanted to be able to clear them, or revert back to the original values without the user having to page refresh. “Sure, just make a copy of the JS object it came from”. Nope!
I wanted a button to clear, or revert back to default some figures in a calculator. The figures come originally from a JS object rather than variables in the script. The obvious answer would be to make a copy of the object.
let originalWaterData = data
The problem is that if I modify any items in the data
object, originalWaterData
will update as well. When JS copies objects, the actual object isn’t copied, merely a reference to the location of the original object. The copy is a shallow copy.
The Methods
In order to make a copy of the original, we need to make a deep copy - to create a completely new object that doesn’t reference the original. There are several workarounds to this. I’ll run through them in order of preference - least to most.
Lodash
Non-natively, you can install Lodash and run the cloneDeep()
function on the object:
let originalWaterData = cloneDeep(data);
I didn’t decide on this as native is best in most cases. I’d prefer not to rely on npm packages unless I absolutely have to. Authors can go AWOL, things can break due to package dependencies. Lodash seems like it’s a pretty stable library, but there’s still 25 packages it depends on.
JSON.parse(JSON.stringify())
There are several methods that will work natively, but without recursion, won’t be able to handle nested data. Object spread, assign, map all come to mind. Until recently, the go to method if you have nested object data is JSON.parse(JSON.stringify()). There are a few caveats to the usage though. Simply run the following on your data:
let originalWaterData = JSON.parse(JSON.stringify(data));
If your object has complex data such as Date
, functions, undefined
, Infinity
and more, you may get some data loss. Mine didn’t, and this method worked for me.
structuredClone()
Chat GPT didn’t propose the modern method: structuredClone()
, presumably due to its cutoff being September 2021. However, it appears that this method is working in all modern browsers.
let originalWaterData = structuredClone(data);
This method will preserve any Date
, function etc data and should be your method of deep copying objects.
According to the MDN docs however:
note that structuredClone() isn’t a feature of the JavaScript language itself — instead it’s a feature of browsers and any other JavaScript runtimes that implement a global object like window.
Links
- Stack Overflow - What is the most efficient way to clone an object in JavaScript
- Mozilla MDN Docs