说说你对深浅拷贝的理解?并实现一个对数组和对象深拷贝的方法

深浅拷贝的理解 (前端开发)

在 JavaScript 中,赋值操作、浅拷贝和深拷贝都是复制数据的不同方式,它们对原始值和引用值(对象、数组)的处理方式不同,导致结果差异很大。

1. 赋值:

  • 只是简单地创建了一个指向相同内存地址的指针。修改其中一个变量会影响另一个变量,因为它们指向同一个数据。
  • 适用于原始值(数字、字符串、布尔值、null、undefined、Symbol),因为它们的值存储在变量本身。
  • 对引用值来说,赋值只是复制了引用,而不是数据本身。

2. 浅拷贝:

  • 创建了一个新的变量,并将原始值的属性值复制到新变量中。
  • 对于原始值,浅拷贝和赋值的效果相同。
  • 对于引用值,浅拷贝只复制了对象的第一层属性。如果属性是原始值,则复制值;如果属性是引用值,则复制引用,这意味着修改新变量的嵌套属性会影响原始变量。

3. 深拷贝:

  • 创建了一个全新的变量,并将原始值及其所有嵌套属性的值都递归地复制到新变量中。
  • 对于原始值,深拷贝和赋值/浅拷贝的效果相同。
  • 对于引用值,深拷贝会创建一个完全独立的副本,修改新变量不会影响原始变量,反之亦然。

深拷贝方法实现 (前端开发)

以下是一个通用的深拷贝函数 deepClone,可以处理数组和对象,并递归处理嵌套的引用值:

function deepClone(obj) {
  // 处理 null、undefined 和原始值
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }

  // 创建新对象或数组
  const clonedObj = Array.isArray(obj) ? [] : {};

  // 递归复制属性
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clonedObj[key] = deepClone(obj[key]);
    }
  }

  return clonedObj;
}


// 测试用例
const originalArray = [1, 2, { a: 3, b: [4, 5] }];
const clonedArray = deepClone(originalArray);

clonedArray[2].a = 6;
clonedArray[2].b.push(6);

console.log("Original Array:", originalArray);
console.log("Cloned Array:", clonedArray);


const originalObject = { a: 1, b: { c: 2, d: [3, 4] } };
const clonedObject = deepClone(originalObject);

clonedObject.b.c = 5;
clonedObject.b.d.push(5);

console.log("Original Object:", originalObject);
console.log("Cloned Object:", clonedObject);


// 处理循环引用 (简化版,更健壮的方案需要使用 WeakMap)
function deepCloneWithCycleCheck(obj, seen = new Set()) {
    if (typeof obj !== "object" || obj === null || seen.has(obj)) {
        return obj;
    }
    seen.add(obj);
    const clonedObj = Array.isArray(obj) ? [] : {};
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            clonedObj[key] = deepCloneWithCycleCheck(obj[key], seen);
        }
    }
    return clonedObj;
}

const objWithCycle = { a: 1 };
objWithCycle.b = objWithCycle;

const clonedObjWithCycle = deepCloneWithCycleCheck(objWithCycle);
console.log("Original Object with Cycle:", objWithCycle);
console.log("Cloned Object with Cycle:", clonedObjWithCycle);

关键点:

  • 使用递归处理嵌套对象和数组。
  • 使用 hasOwnProperty 确保只复制对象自身的属性,而不是原型链上的属性。
  • 区分数组和对象,创建对应的空数组或空对象。
  • 添加了deepCloneWithCycleCheck 函数来简要展示如何处理循环引用,更完善的循环引用处理需要更复杂的逻辑,例如使用 WeakMap 来跟踪已访问的对象。

这个 deepClone 函数提供了一个基本的深拷贝实现。对于更复杂的数据结构(例如包含日期、正则表达式、函数等),需要进行额外的处理。 一些库,例如 Lodash 的 cloneDeep 函数,提供了更强大和全面的深拷贝功能。 根据你的具体需求

posted @   王铁柱6  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示