JavaScript Deep Copy Implementation Guide for Interview Assessments
Shallow vs Deep Copy
Shallow copy creates a new object with an exact duplicate of the original object's top-level property values. For primitive type porperties, the actual value is copied, while for reference type properties, only the memory pointer is copied. Modifying nested reference values in the copied object will alter the corresponding value in the original object.
Deep copy generates a full, independent duplicate of the source object from memory, allocating separate heap space for the new copy. Changes made to the deep copied object will have no impact on the original source object.
Common Off-the-Shelf Deep Copy Implementations
JSON Serialization/Deserialization
This approach first converts the source object to a JSON string via JSON.stringify(), then parses the string back into a new JavaScript object with JSON.parse(). The newly created object ocupies separate memory space, achieving deep copy for eligible data.
const sourceObj = {
username: "Li Ming",
grades: {
physics: 98,
chemistry: 92
}
};
const copiedObj = JSON.parse(JSON.stringify(sourceObj));
copiedObj.grades.physics = 65;
console.log("Original object: ", sourceObj);
// Output: Original object: { username: 'Li Ming', grades: { physics: 98, chemistry: 92 } }
console.log("Copied object: ", copiedObj);
// Output: Copied object: { username: 'Li Ming', grades: { physics: 65, chemistry: 92 } }
Key limitations of this method:
- Omits properties with
undefinedvalues - Fails to serialize function properties
- Does not correctly copy RegExp instances
- Throws an error when processing objects with circular references
- Drops all Symbol-type properties
Lodash cloneDeep Utility
The widely used JavaScript utility library Lodash provides the _.cloneDeep method, a production-ready implementation that supports deep copy for nearly all common JavaScript data types.
import lodash from 'lodash';
const inventory = {
productId: "P-2024-001",
stockInfo: {
warehouseA: 120,
warehouseB: 87
}
};
const inventoryCopy = lodash.cloneDeep(inventory);
This implementation covers all edge cases the JSON serialization approach fails to handle, with no common limitations for standard business use cases.
Handwritten Deep Copy Implementations
Basic Recursive Version
This minimal implementation handles plain objects and arrays, meeting the requirements for most basic interview scenarios.
function basicDeepClone(target) {
// Return primitive values directly
if (typeof target !== 'object' || target === null) {
return target;
}
// Initialize container matching input type
const clonedResult = Array.isArray(target) ? [] : {};
for (const key in target) {
if (target.hasOwnProperty(key)) {
clonedResult[key] = basicDeepClone(target[key]);
}
}
return clonedResult;
}
Limitations of the basic version include no support for circular references, special reference types (Date, RegExp, Function), and potential performance bottlenecks for extremely deeply nested objects.
Advanced Edge Case Support Version
This iteration adds handling for common edge cases, including circular references and special built-in object types:
function advancedDeepClone(target, cache = new WeakMap()) {
// Return primitive type values directly
if (typeof target !== 'object' || target === null) return target;
// Handle special built-in reference types
if (target instanceof Date) return new Date(target);
if (target instanceof RegExp) return new RegExp(target);
// Return cached value to avoid infinite loops from circular references
if (cache.has(target)) return cache.get(target);
// Initialize new object or array container
const clonedOutput = Array.isArray(target) ? [] : {};
cache.set(target, clonedOutput);
// Recursively copy all own properties
for (const key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
clonedOutput[key] = advancedDeepClone(target[key], cache);
}
}
return clonedOutput;
}