深拷贝优化代码

深拷贝意味着我们要复制一个对象,包括它的所有属性,以及属性的属性,以此类推。我们不能简单地将对象的引用复制到新变量,因为这样做只会复制引用,而不会复制对象本身。 

function deepClone(obj, visited = new WeakMap()) {
  // 如果是基本类型或null,则直接返回
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // 防止循环引用
  if (visited.has(obj)) {
    return visited.get(obj);
  }

  let clone;

  // 处理数组
  if (Array.isArray(obj)) {
    clone = [];
    visited.set(obj, clone);
    for (let i = 0; i < obj.length; i++) {
      clone[i] = deepClone(obj[i], visited);
    }
    return clone;
  }

  // 处理对象
  clone = {};
  visited.set(obj, clone);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key], visited);
    }
  }

  return clone;
}

这个函数接受一个参数 obj,代表要拷贝的对象。它使用递归的方式遍历对象的所有属性,并创建一个新的对象,将原对象的属性逐个复制到新对象中。

关键点是处理了循环引用,避免进入无限递归。我们使用 visited 作为一个映射表,记录已经访问过的对象,防止循环引用时陷入无限递归。这样,每次递归时都先检查 visited,如果已经访问过,就直接返回拷贝的结果,避免重复拷贝。


防止无限递归是为了避免陷入无限循环,因为在递归的过程中,如果不进行循环引用的检查,可能会导致代码陷入永远不会结束的递归循环,进而导致程序崩溃或进程被终止。

无限递归通常是因为在对象的属性间存在循环引用,例如对象 A 的一个属性指向对象 B,而对象 B 的一个属性又指向对象 A。如果我们在拷贝对象时不处理这种循环引用,就会陷入无限递归,不断地进入拷贝过程,直到栈溢出或程序崩溃。

以下是一个简单的例子来说明无限递归是如何产生的:

const objA = {};
const objB = {};

objA.circularRef = objB;  // 对象A引用对象B
objB.circularRef = objA;  // 对象B引用对象A

const clonedObj = deepClone(objA);  // 尝试深拷贝对象A及其引用的对象B

在这个例子中,objAobjB 彼此引用,如果我们尝试深拷贝 objA,就会进入无限递归,因为拷贝 objA 时会拷贝其引用的 objB,而拷贝 objB 时会拷贝其引用的 objA,以此类推,导致无限循环。

因此,防止无限递归是深拷贝实现的一个重要步骤,避免了陷入无限递归的情况,确保拷贝过程能够顺利进行并完成。

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