手写深拷贝函数

在 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 是基本数据类型(如 numberstringboolean 等)或者为 null,直接返回即可。
    • 这是因为基本数据类型是按值传递的,不需要深拷贝。
  2. 防止循环引用

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

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

    • 遍历目标对象的所有属性(使用 for...inhasOwnProperty 检查自有属性)。
    • 对每个属性值递归调用 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. 特殊对象

    • 上述实现未考虑 DateRegExpMapSet 等特殊对象。
    • 如果需要支持这些类型,可以扩展代码逻辑。

支持特殊对象的改进版

以下是一个支持更多类型的深拷贝函数:

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 综合教程】 - 【其他大屏】
相关推荐
暖木生晖2 小时前
flex-wrap子元素是否换行
javascript·css·css3·flex
gnip3 小时前
浏览器跨标签页通信方案详解
前端·javascript
gnip3 小时前
运行时模块批量导入
前端·javascript
逆风优雅4 小时前
vue实现模拟 ai 对话功能
前端·javascript·html
这是个栗子4 小时前
【问题解决】Vue调试工具Vue Devtools插件安装后不显示
前端·javascript·vue.js
姑苏洛言5 小时前
待办事项小程序开发
前端·javascript
Warren987 小时前
公司项目用户密码加密方案推荐(兼顾安全、可靠与通用性)
java·开发语言·前端·javascript·vue.js·python·安全
还是大剑师兰特8 小时前
Node.js面试题及详细答案120题(16-30) -- 核心模块篇
node.js·大剑师·nodejs面试题
1024小神9 小时前
vue3 + vite项目,如果在build的时候对代码加密混淆
前端·javascript
轻语呢喃9 小时前
useRef :掌握 DOM 访问与持久化状态的利器
前端·javascript·react.js