热搜:前端 nest neovim nvim

深拷贝如何解决循环引用?

lxf2023-06-20 02:37:49

先来看看例子:

function deepCopy(obj) {
  const res = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (typeof obj[key] === "object") {
      res[key] = deepCopy(obj[key]);
    } else {
      res[key] = obj[key];
    }
  }
  return res;
}
var obj = {
  a: 1,
  b: 2,
  c: [1, 2, 3],
  d: { aa: 1, bb: 2 },
};
obj.e = obj;
console.log("obj", obj); // 不会报错

const objCopy = deepCopy(obj);
console.log(objCopy); //Uncaught RangeError: Maximum call stack size exceeded

从例子可以看到,当存在循环引用的时候,deepCopy 会报错,栈溢出。

  • obj 对象存在循环引用时,打印它时是不会栈溢出
  • 深拷贝 obj 时,才会导致栈溢出

循环应用问题解决

即:目标对象存在循环应用时报错处理大家都知道,对象的 key 是不能是对象的。

{{a:1}:2}
// Uncaught SyntaxError: Unexpected token ':'
  • 解决办法一:使用weakmap 解决循环引用问题,我们可以额外开辟一个存储空间,来存储当前对象和拷贝对象的对应关系

这个存储空间,需要可以存储 key-value 形式的数据,且 key 可以是一个引用类型,我们可以选择 weakMap 这种数据结构:

  • 检查 weakMap 中有无克隆过的对象。
  • 有,直接返回
  • 没有,将当前对象作为 key,克隆对象作为 value 进行存储
  • 继续克隆
function isObject(obj) {
  return (typeof obj === "object" || typeof obj === "function") && obj !== null;
}
function cloneDeep(source, hash = new WeakMap()) {
  if (!isObject(source)) return source;
  if (hash.has(source)) return hash.get(source); // 新增代码,查哈希表

  var target = Array.isArray(source) ? [] : {};
  hash.set(source, target); // 新增代码,哈希表设值

  for (var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (isObject(source[key])) {
        target[key] = cloneDeep(source[key], hash); // 新增代码,传入哈希表
      } else {
        target[key] = source[key];
      }
    }
  }
  return target;
}
  • 解决办法二:可以使用 set,发现相同的对象直接赋值,也可以用 Map
const o = { a: 1, b: 2 };
o.c = o;

function isPrimitive(val) {
  return Object(val) !== val;
}
const set = new Set();
function clone(obj) {
  const copied = {};
  for (const [key, value] of Object.entries(obj)) {
    if (isPrimitive(value)) {
      copied[key] = value;
    } else {
      if (set.has(value)) {
        copied[key] = { ...value };
      } else {
        set.add(value);
        copied[key] = clone(value);
      }
    }
  }
  return copied;
}
本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!