如何判断一个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;
}

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

相关推荐
zzz_23683 分钟前
个人 AI 记忆如何跨工具复用:用 Markdown、索引和 Skill 搭一个可治理的记忆库
前端·人工智能·react.js·前端框架·agent·agent测评
剑之所向2 小时前
.NET 官方`System.Threading.Channels`
前端·javascript·数据库
计算机魔术师2 小时前
GPT-6 Astra幻觉砍到2%,却被一种老招数轻松绕过
前端
cjy0001113 小时前
2026AI 产品如何从一次性 Demo 变成可重复使用的业务工具?
前端·人工智能·fde
IT_陈寒3 小时前
React的状态更新坑得我差点加班到天亮
前端·人工智能·后端
风骏时光牛马3 小时前
深挖底层逻辑:XX源码深度拆解分析
前端
电商API_180079052473 小时前
电商商品价格监控工具淘宝京东商品价格抓取API项目实操分享
java·大数据·开发语言·前端·数据挖掘
sxmas3 小时前
用状态机与DAG建模四阶段业务流程:以MIND模型为例
前端
倔强的石头1064 小时前
【Linux指南】动静态库系列(七):符号表与重定位:链接器如何把函数调用接起来
linux·前端·javascript
a1117765 小时前
3D 脑图谱 / Bilingual 3D Brain Atlas 项目
前端