文章中英模式
布鲁斯前端JS面试题目 - 深拷贝与浅拷贝深入解析
深入解析 JavaScript 中的深拷贝与浅拷贝机制,包含实现原理、性能考量、React 应用场景,以及面试常见问题的完整解答。
文章中英模式
懒得看文章?那就来看视频吧
基本概念
在 JavaScript 中,变量赋值时会根据数据类型采用不同的复制方式:
- •
基本类型
:直接复制值(number、string、boolean、null、undefined、symbol) - •
引用类型
:复制引用地址(object、array、function)
浅拷贝 (Shallow Copy)
只复制第一层的值,嵌套对象仍然共享引用地址。常见方法:
// 1. Object.assign()
const original = { name: 'Bruce', info: { age: 25 } };
const copy1 = Object.assign({}, original);
// 2. 展开运算符
const copy2 = { ...original };
// 3. Array 方法
const arr = [1, [2, 3]];
const arrCopy1 = Array.from(arr);
const arrCopy2 = arr.slice();
深拷贝 (Deep Copy)
递归复制所有层级的值,创建完全独立的新对象。常见方法:
// 1. structuredClone (推荐,但需注意浏览器支持)
const deepCopy1 = structuredClone(original);
// 2. JSON 方法 (有限制)
const deepCopy2 = JSON.parse(JSON.stringify(original));
// 3. 使用 Lodash 函数库
// 需先安装: npm install lodash
import _ from 'lodash';
const deepCopy3 = _.cloneDeep(original);
// 4. 递归实现
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;
}
🔥 常见面试题目
(一)浅拷贝和深拷贝的区别?
解答:
const original = {
name: 'Bruce',
info: { age: 25 }
};
// 浅拷贝
const shallow = { ...original };
shallow.info.age = 26;
console.log(original.info.age); // 26 - 原对象被修改
// 深拷贝
const deep = structuredClone(original);
deep.info.age = 27;
console.log(original.info.age); // 26 - 原对象不受影响
(二)为什么不建议使用 JSON.parse(JSON.stringify()) 进行深拷贝?
解答:JSON 方法有以下限制:
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 - 函数丢失
console.log(copy.symbol); // undefined - Symbol 丢失
console.log(copy.undefined); // undefined - undefined 丢失
console.log(copy.date); // 字符串 - 不再是 Date 对象
console.log(copy.regexp); // {} - 正则表达式变成空对象
console.log(copy[Symbol('key')]); // undefined - Symbol key 丢失
(三)如何实现一个深拷贝函数?
解答:
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