iTranslated by AI
What Is the Best Way to Copy and Edit Objects?
Conclusion: Copying with structuredClone and then editing the object seems to be well-balanced from a performance perspective.
What I wanted to verify
I wanted to investigate which method is the fastest when you want to copy an object like the following and change a property in a deep hierarchy.
const obj = {
prop: { sub: { val: '' } },
prop2: { sub: { val: '' } },
};
Here are the candidates for the copying method:
- Manually using the spread operator
- Using
structuredClone - Using
immer -
JSON.parse(JSON.stringify(obj))[1]
Note that in this case, we are not deep-copying everything; it is acceptable to use shallow copies for parts that do not change. In other words, prop2 can be a shallow copy. This is because I encountered such a case in actual work.
HTML file used for verification (verbatim)
<!DOCTYPE html>
<script type="module">
import { produce } from 'https://unpkg.com/immer@10.0.2/dist/immer.production.mjs';
const obj = {
prop: { sub: { val: '' } },
prop2: { sub: { val: '' } },
};
console.time('raw');
for (let i = 0; i < 1e5; i++) {
const copied = {
...obj,
prop: { ...obj.prop, sub: { ...obj.prop.sub, val: `${i}_dayo` } },
};
}
console.timeEnd('raw');
console.time('structuredClone');
for (let i = 0; i < 1e5; i++) {
const copied = structuredClone(obj);
copied.prop.sub.val = `${i}_dayo`;
}
console.timeEnd('structuredClone');
console.time('immer');
for (let i = 0; i < 1e5; i++) {
const copied = produce(obj, (draft) => {
draft.prop.sub.val = `${i}_dayo`;
});
}
console.timeEnd('immer');
console.time('JSON.stringify');
for (let i = 0; i < 1e5; i++) {
const copied = JSON.parse(JSON.stringify(obj));
copied.prop.sub.val = `${i}_dayo`;
}
console.timeEnd('JSON.stringify');
</script>
Results
Measurements were taken on Chrome for macOS. The results were as follows.
| Method | Time |
|---|---|
| raw | 8.72290039062 ms |
| JSON.stringify | 47.80322265625 ms |
| structuredClone | 116.84326171875 ms |
| immer | 152.74682617875 ms |
Increasing the number of properties slightly resulted in this.
| Method | Time |
|---|---|
| raw | 11.43896484 ms |
| JSON.stringify | 277.97060546 ms |
| immer | 279.44091796 ms |
| structuredClone | 343.45703125 ms |
Analysis
Regardless of the object size, the method of manually copying with the spread operator seemed to be the fastest.
...I'd like to say that, but the requirement was that the added properties could be shallow-copied. This might be why only "raw" didn't see much change in speed.
Methods other than the spread operator seem to depend heavily on the size of the object. However, the other three methods were almost in the same order of magnitude, so which one to use seems to be a matter of preference.
Conclusion: structuredClone seems to be well-balanced
While I've discussed various points, I think it is best to use structuredClone as long as it doesn't become a performance bottleneck. The code is simpler, and the performance is not as bad as one might think. Almost all modern browsers support structuredClone. It seems like a very well-balanced and solid choice.
-
This method should not really be used as it has issues such as not being able to preserve
Datetypes. For example, if you tryJSON.parse(JSON.stringify(new Date())), the result is a string value. ↩︎
Discussion