在JavaScript中,深浅拷贝是处理对象复制的重要概念,主要用于避免引用类型数据共享带来的副作用。以下从定义、区别、实现方法和注意事项进行详细讲解。
1. 浅拷贝(Shallow Copy)
-
定义:创建一个新对象,只复制对象的第一层属性(基本类型值会被复制,引用类型值则复制其引用地址)。因此,如果原对象的属性包含嵌套对象,修改新对象的嵌套属性会影响原对象。
-
实现方法:
-
对象浅拷贝:
-
使用 Object.assign():const newObj = Object.assign({}, originalObj)
;
-
使用展开运算符(ES6):const newObj = { ...originalObj }
;
-
-
数组浅拷贝:
-
使用 Array.from():const newArr = Array.from(originalArr)
;
-
使用 slice():const newArr = originalArr.slice()
;
-
使用展开运算符:const newArr = [...originalArr]
;
-
-
示例代码:
javascript
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
shallowCopy.b.c = 3; // 修改嵌套属性
console.log(obj.b.c); // 输出 3,原对象也被修改
-
特点:
-
简单高效,适合拷贝简单结构。
-
缺点:嵌套对象共享引用,可能导致意外修改。
-
2. 深拷贝(Deep Copy)
定义:创建一个新对象,并递归地复制所有层级属性(包括嵌套对象),使得新对象与原始对象完全独立。修改新对象不会影响原对象。
-
实现方法:
-
JSON方法(简单但有限制):
-
const newObj = JSON.parse(JSON.stringify(originalObj));
-
缺点:无法复制函数、undefined、Symbol、循环引用或日期对象(会被转为字符串)。
-
-
-
递归手动实现:
- 自定义函数处理各种类型:
javascript
function deepClone(obj, map = new Map()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj); // 处理循环引用
const clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map);
}
}
return clone;
}
const newObj = deepClone(originalObj);
示例代码:
javascript
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
deepCopy.b.c = 3; // 修改嵌套属性
console.log(obj.b.c); // 输出 2,原对象不受影响
-
特点:
-
完全隔离数据,适合复杂对象。
-
缺点:性能开销大(尤其递归深层次对象),需处理边界情况如循环引用。
-
structuredClone方法
在 JavaScript 中,structuredClone()
是现代浏览器和 Node.js(v17+)提供的原生深拷贝 API,专门用于解决传统深拷贝方法的局限性。以下是详细说明:
1. 为何需要 structuredClone
?
-
传统深拷贝的不足:
-
JSON.parse(JSON.stringify())
会丢失函数、undefined
、Symbol
等类型 -
递归实现需手动处理循环引用、特殊对象(如 Date/Map/Set)
-
-
structuredClone
直接内置于 JavaScript 运行时,无需第三方库
2.核心功能与优势
-
深拷贝实现:递归复制所有层级(包括嵌套对象、数组、Map、Set等),生成完全独立的新对象。
-
支持复杂类型:
-
✅ 支持
Date
、RegExp
、ArrayBuffer
、Map
、Set
等类型(JSON方法会丢失这些类型) -
✅ 自动处理循环引用 (如
obj.self = obj
) -
❌ 不支持函数、DOM节点、Error对象(会抛出
DOMException
) -
语法简洁:
-
javascript
const original = { a: 1, b: new Date() };
const clone = structuredClone(original); // 一行代码完成深拷贝
3. 与传统方法的对比
方法 | 支持循环引用 | 保留特殊类型 | 性能 | 安全性 |
---|---|---|---|---|
JSON.parse/stringify |
❌ | ❌ | 中 | 高 |
递归手动实现 | 需额外处理 | ✅ | 低 | 中 |
structuredClone |
✅ | ✅ | 高 | 高 |
3. 关键区别与注意事项
-
核心区别:
-
浅拷贝:只复制一层,嵌套对象共享引用。
-
深拷贝:复制所有层级,嵌套对象独立。
-
-
使用场景:
-
浅拷贝:状态管理(如React的浅比较)、简单数据传递。
-
深拷贝:数据持久化、不可变数据更新(如Redux reducer)。
-
-
常见陷阱:
-
循环引用:手动深拷贝需使用WeakMap或Map避免无限递归。
-
性能:深拷贝大对象可能阻塞主线程,优先考虑浅拷贝或Immutable.js等库。
-
类型兼容:JSON方法会丢失特殊类型(如函数),需手动处理。
-