在 JavaScript 中,浅拷贝(Shallow Copy) 和 深拷贝(Deep Copy) 是处理对象复制的两种方式,它们的区别在于是否递归复制对象的嵌套属性。
浅拷贝
特点:只复制对象的第一层属性,嵌套对象仍然是引用(共享内存)。
1. 手写浅拷贝实现
ini
function shallowCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj; // 基本类型直接返回
}
const copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key]; // 仅复制第一层
}
}
return copy;
}
// 测试
const obj = { a: 1, b: { c: 2 } };
const copy = shallowCopy(obj);
copy.b.c = 3;
console.log(obj.b.c); // 3(原对象也被修改)
2. JS 内置的浅拷贝方法
Object.assign({}, obj)
ini
const obj = { a: 1, b: { c: 2 } };
const copy = Object.assign({}, obj);
copy.b.c = 3; // 原对象也被修改
[...array]
(数组扩展运算符)
ini
const arr = [1, 2, { a: 3 }];
const copy = [...arr];
copy[2].a = 4; // 原数组也被修改
Array.prototype.slice()
ini
const arr = [1, 2, { a: 3 }];
const copy = arr.slice();
copy[2].a = 4; // 原数组也被修改
深拷贝
特点:递归复制所有层级的属性,新旧对象完全独立。
1. 手写深拷贝实现
ini
function deepCopy(obj, cache = new WeakMap()) {
if (typeof obj !== 'object' || obj === null) {
return obj; // 基本类型直接返回
}
if (cache.has(obj)) {
return cache.get(obj); // 避免循环引用
}
const copy = Array.isArray(obj) ? [] : {};
cache.set(obj, copy); // 缓存对象,防止循环引用
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key], cache); // 递归复制
}
}
return copy;
}
// 测试
const obj = { a: 1, b: { c: 2 } };
const copy = deepCopy(obj);
copy.b.c = 3;
console.log(obj.b.c); // 2(原对象未被修改)
2. JS 内置的深拷贝方法
JSON.parse(JSON.stringify(obj))
(最简单但有限制)
ini
const obj = { a: 1, b: { c: 2 } };
const copy = JSON.parse(JSON.stringify(obj));
copy.b.c = 3; // 原对象不受影响
缺点:
-
- 不能复制
Function
、RegExp
、Date
、undefined
、Symbol
等特殊类型。 - 不能处理循环引用(如
obj.self = obj
)。
- 不能复制
structuredClone()
(现代浏览器支持)
ini
const obj = { a: 1, b: { c: 2 } };
const copy = structuredClone(obj); // 深拷贝
copy.b.c = 3; // 原对象不受影响
优点:
-
- 支持
Date
、RegExp
、Map
、Set
等复杂类型。 - 能处理循环引用。
缺点: - 不能复制函数(
Function
)。
- 支持
深拷贝 vs 浅拷贝对比
特性 | 浅拷贝 | 深拷贝 |
---|---|---|
复制层级 | 仅第一层 | 递归所有层级 |
内存占用 | 低(共享嵌套对象) | 高(完全独立) |
修改影响 | 原对象可能被修改 | 原对象不受影响 |
适用场景 | 简单对象,无嵌套 | 复杂对象,需完全独立 |
如何选择?
- 浅拷贝 :适用于简单对象,如
{ a: 1, b: 2 }
(无嵌套)。 - 深拷贝 :适用于复杂对象,如
{ a: 1, b: { c: 2 } }
(有嵌套)。
推荐方法:
- 浅拷贝 :
Object.assign()
或[...arr]
。 - 深拷贝 :
structuredClone()
(现代浏览器)或手写递归深拷贝。
总结
- 浅拷贝:仅复制第一层,适用于简单数据。
- 深拷贝:递归复制所有层级,适用于复杂数据。
- 结构化克隆 (
structuredClone
)是最方便的深拷贝方式,但不支持函数。