Quick comparison of methods
| Method | Handles Dates | Handles functions | Handles circular refs | Performance |
|---|
| JSON | ❌ becomes string | ❌ removed | ❌ error | fast |
| structuredClone (modern) | ✅ | ❌ | ✅ | fast |
| _.cloneDeep (Lodash) | ✅ | ✅ | ✅ | moderate |
| Recursive manual | custom | custom | tricky | slow |
🏆 Best for 99% of cases – structuredClone (built-in, Node 17+/all modern browsers)
js
1const clone = structuredClone(original);
2console.log(clone.date instanceof Date); // true
3// But functions are still lost (they are not cloneable)
1const clone = structuredClone(original);
2console.log(clone.date instanceof Date); // true
3// But functions are still lost (they are not cloneable)
If you need to copy functions (rarely necessary – better to restructure)
Use Lodash:
js
1import _ from 'lodash';
2const clone = _.cloneDeep(original);
1import _ from 'lodash';
2const clone = _.cloneDeep(original);
Custom recursive for Dates and RegExps (educational)
js
1function deepClone(obj) {
2 if (obj === null || typeof obj !== 'object') return obj;
3 if (obj instanceof Date) return new Date(obj);
4 if (obj instanceof RegExp) return new RegExp(obj);
5 if (Array.isArray(obj)) return obj.map(deepClone);
6
7 const cloned = {};
8 for (let key in obj) {
9 if (obj.hasOwnProperty(key)) {
10 cloned[key] = deepClone(obj[key]);
11 }
12 }
13 return cloned;
14}
1function deepClone(obj) {
2 if (obj === null || typeof obj !== 'object') return obj;
3 if (obj instanceof Date) return new Date(obj);
4 if (obj instanceof RegExp) return new RegExp(obj);
5 if (Array.isArray(obj)) return obj.map(deepClone);
6
7 const cloned = {};
8 for (let key in obj) {
9 if (obj.hasOwnProperty(key)) {
10 cloned[key] = deepClone(obj[key]);
11 }
12 }
13 return cloned;
14}
Note: does not handle circular references.
✅ Recommendation: Use structuredClone for most data. If you need functions, reconsider your architecture – functions imply behavior, which usually shouldn't be deep-copied.