EN/CH Mode
BRUCE_FE JS Interview Notes - Deep Copy vs Shallow Copy
In-depth analysis of deep and shallow copy mechanisms in JavaScript, including implementation principles, performance considerations, React application scenarios, and complete answers to common interview questions.
EN/CH Mode
Lazy to read articles? Then watch videos!
Basic Concepts
In JavaScript, different copying methods are used when assigning variables based on data types:
- •
Primitive types
: Direct value copying (number, string, boolean, null, undefined, symbol) - •
Reference types
: Copy reference addresses (object, array, function)
Shallow Copy
Only copies the first level values; nested objects still share reference addresses. Common methods:
// 1. Object.assign()
const original = { name: 'Bruce', info: { age: 25 } };
const copy1 = Object.assign({}, original);
// 2. Spread operator
const copy2 = { ...original };
// 3. Array methods
const arr = [1, [2, 3]];
const arrCopy1 = Array.from(arr);
const arrCopy2 = arr.slice();
Deep Copy
Recursively copies values at all levels, creating completely independent new objects. Common methods:
// 1. structuredClone (recommended, but check browser support)
const deepCopy1 = structuredClone(original);
// 2. JSON methods (with limitations)
const deepCopy2 = JSON.parse(JSON.stringify(original));
// 3. Using Lodash library
// Install first: npm install lodash
import _ from 'lodash';
const deepCopy3 = _.cloneDeep(original);
// 4. Recursive implementation
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
copy[key] = deepClone(obj[key]);
}
}
return copy;
}
🔥 Common Interview Questions
(1) What's the difference between shallow copy and deep copy?
Answer:
const original = {
name: 'Bruce',
info: { age: 25 }
};
// Shallow copy
const shallow = { ...original };
shallow.info.age = 26;
console.log(original.info.age); // 26 - original object is modified
// Deep copy
const deep = structuredClone(original);
deep.info.age = 27;
console.log(original.info.age); // 26 - original object is not affected
(2) Why is JSON.parse(JSON.stringify()) not recommended for deep copying?
Answer: JSON methods have the following limitations:
const obj = {
func: () => console.log('Hello'),
symbol: Symbol('test'),
undefined: undefined,
date: new Date(),
regexp: /test/,
[Symbol('key')]: 'value'
};
const copy = JSON.parse(JSON.stringify(obj));
console.log(copy.func); // undefined - functions are lost
console.log(copy.symbol); // undefined - Symbols are lost
console.log(copy.undefined); // undefined - undefined values are lost
console.log(copy.date); // string - no longer a Date object
console.log(copy.regexp); // {} - regular expressions become empty objects
console.log(copy[Symbol('key')]); // undefined - Symbol keys are lost
(3) How to implement a deep copy function?
Answer:
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
const copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
copy[key] = deepClone(obj[key]);
}
}
return copy;
}
function deepClone2(value, hash = new WeakMap()) {
// Handle null and non-objects
if (value === null || typeof value !== 'object') return value;
// Handle Date objects
if (value instanceof Date) return new Date(value);
// Handle RegExp objects
if (value instanceof RegExp) return new RegExp(value);
// Handle circular references
if (hash.has(value)) return hash.get(value);
// Create new array or object
const copy = Array.isArray(value) ? [] : {};
// Record processed objects to avoid circular references
hash.set(value, copy);
// Recursively process all properties
Object.entries(value).forEach(([key, val]) => {
copy[key] = deepClone(val, hash);
});
return copy;
}
// Usage example
const obj = {
array: [1, { a: 2 }],
date: new Date(),
regexp: /test/,
func: function() {},
nested: {
deep: { value: 123 }
}
};
// Create circular reference
obj.self = obj;
const cloned = deepClone(obj);
console.log(cloned.nested.deep.value); // 123
console.log(cloned.self === cloned); // true - maintains circular reference
console.log(cloned.self !== obj); // true - is a new object