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, 等于自身的对象

你可能感兴趣的:(javascript,开发语言,ecmascript)