手写深拷贝函数

在 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;
}

代码解析

  1. 基本数据类型处理

    • 如果 target 是基本数据类型(如 number、string、boolean 等)或者为 null,直接返回即可。
    • 这是因为基本数据类型是按值传递的,不需要深拷贝。
  2. 防止循环引用

    • 使用 WeakMap 来存储已经拷贝过的对象。
    • 如果发现当前对象已经在 map 中存在,则直接返回它的拷贝,避免无限递归。
  3. 初始化结果容器

    • 如果目标是一个数组,则初始化一个空数组。
    • 如果目标是一个对象,则初始化一个空对象。
  4. 递归拷贝

    • 遍历目标对象的所有属性(使用 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(循环引用处理正确)

注意事项

  1. 性能问题

    • 深拷贝可能会消耗大量内存,特别是对于大型对象或数组。
    • 可以根据实际需求优化,例如只拷贝特定深度的对象。
  2. 特殊对象

    • 上述实现未考虑 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 综合教程】 - 【其他大屏】
相关推荐
麦麦麦当劳大王10 小时前
【油猴脚本】Boss直聘 岗位职责复制
开发语言·前端·javascript
只睡四小时11 小时前
Three.js Sub-tick:漏判 60.7%→0
开发语言·javascript·性能优化·ecmascript·游戏开发·three.js·碰撞检测
excel12 小时前
基于 GPT 的自动发布文章接口方案:从一句话或一张图片生成并发布内容
前端·javascript·后端
OpsEye18 小时前
大模型 Token 计量不准,是什么原因,怎么解决??
javascript·ai编程
独隅19 小时前
WebStorm Windows 版 React / Next.js 实战替换指南
javascript·windows·webstorm
冷眸_19 小时前
同名食材不能直接相减:一个 JavaScript 用量模型的边界
javascript
apollo_qwe19 小时前
接口超时了,前端为什么不能直接重试?
javascript·http
toooooop81 天前
CRMEB 故障排查笔记:安全网关只放行 GET/POST 怎么办
前端·javascript·vue.js·thinkphp6·crmeb
软件技术NINI1 天前
基于SpringBoot和Vue的项目评审系统
javascript·vue.js·spring boot·后端·spring·毕业设计·毕设
vipxieliang1 天前
JavaScript 模板字符串与标签模板:不只是拼接
前端·javascript