如何判断一个js对象是否存在循环引用

一、背景

在前端JSON.stringfy是我们常用的一个方法,可以将一个对象序列化。 例如将如下对象序列化

javascript 复制代码
const person = { name: 'kalory', age:18}

JSON.stringfy(person)
// 结果
'{"name":"kalory","age":18}'

将一个数组序列化

const arr = [1,2,3,4,5]
// 结果
'[1,2,3,4,5]'

const persons = [{ name: 'kalory', age:18},{ name: 'jack', age:48}]
// 结果
'[{"name":"kalory","age":18},{"name":"jack","age":48}]'

我们发现上面对象是可以使用JSON.stringfy序列化的。

  • 但是如果一个对象存在循环引用,序列化会报错,如下 person对象的owner属性指向了自己,存在循环引用
javascript 复制代码
const person = { name: 'kalory', age:18}
person.onwer = person

我们对上面这个对象进行JSON.stringfy,结果如下,会报错:

我们发现他说不能转化一个"圈结构体为JSON",是因为这个对象的owner属性指向了自己。在转化的时候会变成死循环。

  • 那么我们如果判断一个对象有没有环呢?

二、实现

2.1 思路

我们判断一个对象有没有循环引用,我们其实并不需要在乎对象的key是什么,只需要判断对象的value。如果value是引用数据类型的时候,有没有指向对象的某一值。

所以我们可以先使用Object.values()拿到对象所有values,然后定义一个cache变量用来存储values中的引用数据类型,然后遍历values

如果cache中存在,那么说明这个对象有环 return true,如果不存在并且是引用数据类型,那么我们就加入cache。当values遍历完都没有reutrn那么说明没有环return false

2.2 递归实现

javascript 复制代码
function existCircular(obj) {
  let cache = new Set(); 
  function helper(obj) {
    let values = Object.values(obj);
    for (let i = 0; i < values.length; i++) {
      if (cache.has(values[i])) {
        return true;
      }
      
      // 不是引用数据类型,直接跳过
      if(typeof values[i] !== 'object' || values[i] === null) continue
      cache.add(values[i]);
      
      let flag = helper(values[i]);
      // 如果 flag 是 false, 那么继续遍历,如果是 true,说明已经存在环了, 直接 return true
      if (flag) {
        return true;
      }
    }
    return false;
  }

  return helper(obj);
}

// 测试
const person = { name: 'kalory', age:18}
person.onwer = person

existCircular(person) // true

2.3 BFS实现

javascript 复制代码
const existCircularBFS = (obj) => {
  let cache = new Set();
  let values = [obj];

  while(values.length) {
    const item =  values.shift()
    if (cache.has(item)) {
        return true;
    }
    // 基本数据类型跳过
    if(typeof item !== 'object' || item === null) continue
    cache.add(item);
    // 主要这里 Object.values 拿到的是一个数组,我们需要展开push到values
    // 如果直接 push Object.values(item) 会造成死循话
    values.push(...Object.values(item))
  }
  
  return false;
}

好啦!今天的碎碎念就到这里啦。对你如果有帮助点个关注哦~🧸。

相关推荐
饼饼饼10 小时前
React 组件间传参好痛苦?试试这一套"优雅组合拳":Context 与 Refs 实战
前端
qq_4198540510 小时前
空间网格管理器
前端·javascript·html
qingmiaozhuan10 小时前
电脑录屏没有声音还能补救吗?音频采集链路详解及4种技术方案
前端·电脑·音视频·开发工具·电脑录屏·电脑录屏软件
天若有情67310 小时前
Dev_Portfolio 个人主页html网页源码分享!!!
前端·html·源码·个人主页
李剑一11 小时前
ant-design-vue 1.x 版本换肤功能开发
前端·vue.js·ant design
京东云开发者11 小时前
【Coding生态】从代码托管到 AI 能力底座:与Coding一起共建 AI 研发生态
前端
guhy fighting12 小时前
x-www-form-urlencoded,form-data,raw 表单请求格式的区别
前端·表单请求格式
李明卫杭州12 小时前
Vue2 与 Vue3 自定义指令详解:钩子变化、迁移指南与实战示例
前端·javascript·vue.js
问商十三载12 小时前
大模型GEO内容更新频率:3个节奏规律提收录权重,零成本提30%引用率附更新计划表
前端·人工智能·机器学习
yingyima12 小时前
sed 命令速查手册:从一次午夜事故说起
前端