在 JavaScript 中,深拷贝是指创建一个对象或数组的完全独立副本,包括其嵌套的对象或数组。这意味着修改副本不会影响原始对象。

以下是手写一个通用的深拷贝函数的实现:
深拷贝函数实现
javascript
function deepClone(target, map = new WeakMap()) {
// 如果目标是基本数据类型,直接返回
if (typeof target !== 'object' || target === null) {
return target;
}
// 防止循环引用
if (map.has(target)) {
return map.get(target);
}
// 初始化结果容器
const cloneTarget = Array.isArray(target) ? [] : {};
// 将当前对象存入 map 中
map.set(target, cloneTarget);
// 遍历目标对象的所有属性
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone(target[key], map); // 递归深拷贝
}
}
return cloneTarget;
}
代码解析
-
基本数据类型处理
- 如果
target
是基本数据类型(如number
、string
、boolean
等)或者为null
,直接返回即可。 - 这是因为基本数据类型是按值传递的,不需要深拷贝。
- 如果
-
防止循环引用
- 使用
WeakMap
来存储已经拷贝过的对象。 - 如果发现当前对象已经在
map
中存在,则直接返回它的拷贝,避免无限递归。
- 使用
-
初始化结果容器
- 如果目标是一个数组,则初始化一个空数组。
- 如果目标是一个对象,则初始化一个空对象。
-
递归拷贝
- 遍历目标对象的所有属性(使用
for...in
和hasOwnProperty
检查自有属性)。 - 对每个属性值递归调用
deepClone
,确保嵌套的对象和数组也能被深拷贝。
- 遍历目标对象的所有属性(使用
测试代码
javascript
// 测试对象
const obj = {
name: 'Alice',
age: 25,
hobbies: ['reading', 'coding'],
details: {
address: 'Wonderland',
phone: 123456789
},
circularRef: null // 循环引用
};
obj.circularRef = obj; // 设置循环引用
// 深拷贝
const clonedObj = deepClone(obj);
console.log(clonedObj);
console.log(clonedObj === obj); // false
console.log(clonedObj.details === obj.details); // false
console.log(clonedObj.hobbies === obj.hobbies); // false
console.log(clonedObj.circularRef === clonedObj); // true(循环引用处理正确)
注意事项
-
性能问题
- 深拷贝可能会消耗大量内存,特别是对于大型对象或数组。
- 可以根据实际需求优化,例如只拷贝特定深度的对象。
-
特殊对象
- 上述实现未考虑
Date
、RegExp
、Map
、Set
等特殊对象。 - 如果需要支持这些类型,可以扩展代码逻辑。
- 上述实现未考虑
支持特殊对象的改进版
以下是一个支持更多类型的深拷贝函数:
javascript
function deepClone(target, map = new WeakMap()) {
// 基本数据类型和 null
if (typeof target !== 'object' || target === null) {
return target;
}
// 特殊对象处理
const constructor = target.constructor;
if (/^(Date|RegExp|Map|Set)$/i.test(constructor.name)) {
return new constructor(target);
}
// 防止循环引用
if (map.has(target)) {
return map.get(target);
}
// 初始化结果容器
const cloneTarget = Array.isArray(target) ? [] : {};
map.set(target, cloneTarget);
// 遍历目标对象的所有属性
for (const key in target) {
if (target.hasOwnProperty(key)) {
cloneTarget[key] = deepClone(target[key], map);
}
}
return cloneTarget;
}
通过上述方法,你可以实现一个功能完善的深拷贝函数,并根据实际需求进行扩展!
No. | 大剑师精品GIS教程推荐 |
---|---|
0 | 地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】 |
1 | Openlayers 【入门教程】 - 【源代码+示例 300+】 |
2 | Leaflet 【入门教程】 - 【源代码+图文示例 150+】 |
3 | MapboxGL 【入门教程】 - 【源代码+图文示例150+】 |
4 | Cesium 【入门教程】 - 【源代码+综合教程 200+】 |
5 | threejs 【中文API】 - 【源代码+图文示例200+】 |
6 | Shader 编程 【图文示例 100+】 |
7 | Geoserver 【配置教程 100+】 |
8 | 卫星应用开发教程 【配置+应用教程 100+】 |
9 | GIS数字孪生与大模型 【应用实战 100+】 |
10 | 报表与数字大屏 【Echarts 实战示例】 - 【D3 综合教程】 - 【其他大屏】 |