• JS深拷贝处理日期、正则以及循环引用问题


    一、深拷贝的含义

    深拷贝(deep copy)是指在内存中创建一个完全独立的新对象,并将原对象的所有内容复制到新对象中。相比之下,浅拷贝(shallow copy)只是复制对象的引用,而不是复制对象本身。深拷贝在以下场景中非常有用:

    1. 防止引用共享问题:当多个对象引用同一个对象时,如果对其中一个对象做出修改,会影响其他对象。使用深拷贝可以创建一个完全独立的对象,避免这种共享问题。

    2. 对象状态快照:有时候我们需要对对象的状态进行快照,以便将来能够回滚到特定的状态。深拷贝可以用于创建状态的副本,而不影响原始对象。

    3. 复制可变对象:如果一个对象包含其他可变对象作为其属性,而你需要复制整个对象图,以便修改副本而不会影响原始对象,这时深拷贝非常有用。

    二、深拷贝在前端开发业务场景的中的使用

    1. 状态管理:当使用状态管理库(如Redux、Vuex)时,需要对状态进行深拷贝以避免直接修改原始状态。这样可以确保状态变更的可追溯性和可控性。

    2. 表单数据处理:当从表单中获取数据时,通常需要对数据进行深拷贝。这是因为对象是通过引用传递的,若直接修改表单数据,可能会引发不可预料的问题。通过深拷贝,可以在不修改原始数据的情况下对数据进行处理和验证。

    3. 缓存数据处理:当从缓存中获取对象并进行修改时,使用深拷贝可以避免修改缓存中的原始数据。这对于对缓存进行更新、比较或存储历史数据非常有用。

    4. 避免对象引用共享问题:在前端开发中,多个对象可能引用同一个对象。如果对其中一个对象进行修改,会影响其他对象。深拷贝可以创建独立的对象副本,避免引用共享问题。

    5. 对象传递和传输:在前端开发中,有时候需要将对象传递给其他组件、模块或服务。为了确保传递的对象不受外部修改的影响,可以使用深拷贝进行对象的传递和传输。

    三、深拷贝函数的封装

    function deepClone(obj, cache = new WeakMap()) {
      // 缓存一个map结构, WeakMap不影响垃圾回收, 该回收就回收掉了,可以减少内存泄漏的风险
      /**
       * WeakMap 中的键只能是对象,并且对于键对象的引用是弱引用,
       * 这意味着当键对象不再被引用时,它们将被垃圾回收。
       */
      if (obj === null || typeof obj !== "object") {
        return obj;
      }
      // 处理正则表达式
      if (obj instanceof RegExp) {
        return new RegExp(obj);
      }
      // 处理日期
      if (obj instanceof Date) {
        return new Date(obj);
      }
      // 递归之前先判断一下, 检查是否已经拷贝过该对象
      if (cache.has(obj)) {
        return cache.get(obj);
      }
      const clone = Array.isArray(obj) ? [] : {};
      // 没有缓存情况,将克隆对象添加到缓存
      cache.set(obj, clone);
      for (const key in obj) {
        // 排除原型上的属性
        if (obj.hasOwnProperty(key)) {
          clone[key] = deepClone(obj[key], cache);
        }
      }
      return clone;
    }
    
    const obj = {
      arr: [1, 2, 3],
      a: 4,
      c: /{1, 5}/,
      d: function hello() {
        console.log("say Hello!");
      },
      e: new Date(),
      f: undefined,
      g: null,
    };
    obj.sub = obj;
    obj.arr.push(obj);
    
    const newObj = deepClone(obj);
    console.log(newObj);
    console.log(newObj.arr !== obj.arr); // true
    console.log(newObj.sub !== obj.sub); // true
    console.log(newObj.arr[3] !== obj); // true, push的新数组不等于原来的对象
    console.log(newObj.arr[3] === newObj); // true, 等于自身的对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
  • 相关阅读:
    RapidJson开源库使用
    数据结构与算法之美学习笔记:17 | 跳表:为什么Redis一定要用跳表来实现有序集合?
    自学人工智能编程难吗?
    Ubuntu TDengine集群搭建
    北航计算机软件技术基础课程作业&笔记【5】
    MySQL Insert 后獲得主鍵
    瓴羊,从阿里最佳实践到社会化服务
    ubuntu ffmpeg 合成字幕 字体缺失selecting one more font for
    如何在TestNG中恢复失败的测试用例?
    POST和GET传值的方法
  • 原文地址:https://blog.csdn.net/m0_46219714/article/details/132940587