一、浅拷贝与深拷贝的概念
浅拷贝 (Shallow Copy)
- 只复制对象的第一层属性
- 如果属性是基本类型,拷贝其值
- 如果属性是引用类型,拷贝其内存地址(即共享同一引用)
- 修改拷贝后的对象的引用类型属性会影响原对象
深拷贝 (Deep Copy)
- 递归复制对象的所有层级
- 无论属性是基本类型还是引用类型,都重新创建
- 拷贝后的对象与原对象完全独立,互不影响
二、浅拷贝的实现方法
1. Object.assign()
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);2. 展开运算符(...)
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };3. Array.prototype.slice() (数组)
const arr = [1, 2, [3, 4]];
const shallowCopy = arr.slice();4. Array.prototype.concat() (数组)
const arr = [1, 2, [3, 4]];
const shallowCopy = [].concat(arr);三、深拷贝的实现方法
1. JSON.parse(JSON.stringify()) - 最简单但有局限
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}局限性:
- 不能处理函数、undefined、Symbol
- 不能处理循环引用
- 会丢失对象的constructor,所有构造函数都会指向Object
- 日期对象会变成字符串
2. 递归实现 - 基础版
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const clone = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
}3. 递归实现 - 完整版(处理更多类型)
function deepClone(obj, hash = new WeakMap()) {
// 处理基本类型和null/undefined
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理日期
if (obj instanceof Date) {
return new Date(obj);
}
// 处理正则
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 处理循环引用
if (hash.has(obj)) {
return hash.get(obj);
}
// 处理数组和对象
const clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
// 处理Symbol属性
const symKeys = Object.getOwnPropertySymbols(obj);
if (symKeys.length > 0) {
symKeys.forEach(symKey => {
clone[symKey] = deepClone(obj[symKey], hash);
});
}
// 处理普通属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
return clone;
}4. 使用第三方库
- lodash 的
_.cloneDeep()
const _ = require('lodash');
const deepCopy = _.cloneDeep(originalObj);- jQuery 的
$.extend(true, {}, obj)
const deepCopy = $.extend(true, {}, originalObj);四、深拷贝的注意事项
- 循环引用问题:对象内部有循环引用时,简单递归会导致栈溢出,需要使用WeakMap记录已拷贝对象
- 特殊对象处理:需要特别处理Date、RegExp、Set、Map等内置对象
- 函数拷贝:函数是否需要拷贝取决于具体需求,通常函数是共享的
- 原型链:是否需要保持原型链关系
- 性能考虑:深拷贝是昂贵的操作,特别是对于大型对象
五、实际应用建议
- 对于简单对象且不包含特殊类型,可以使用
JSON.parse(JSON.stringify()) - 对于复杂对象,建议使用lodash的
_.cloneDeep() - 如果性能是关键考虑因素,可以考虑只拷贝需要的部分而非整个对象
六、性能比较
通常性能排序(从快到慢):
- 浅拷贝
- JSON方法(但有局限性)
- 完整的递归深拷贝
- 第三方库(功能最全但稍慢)
















