前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:如何判断一个对象存在"循环引用"?

面试官:如何判断一个对象存在"循环引用"?

作者头像
前端胖头鱼
发布2023-09-06 09:28:24
3710
发布2023-09-06 09:28:24
举报
文章被收录于专栏:胖头鱼学前端胖头鱼学前端

1. 手写62+方法学习JavaScript底层原理

判断一个对象是否存在循环引用已收录至 手写各种源码实现(https://github.com/qianlongo/fe-handwriting),也可以直接点击isCyclic(https://github.com/qianlongo/fe-handwriting/blob/master/51.isCyclic.js)快速查看,目前已有62+手写实现,欢迎一起来学习喔。

2. 不得不说的循环引用

如下图: 相信曾经你也到过类似的问题,循环引用。如果两个对象相互传递引用或者对象的属性引用其本身都有可能会造成循环引用。

在旧的浏览器中循环引用是造成内存泄漏的一个原因,当然随着垃圾收集算法的改进,现在可以很好地处理循环引用,这不再是一个问题。

只需要3分钟时间,本文会您一起学习

  1. 哪些情况可能会造成循环引用(重要)?
  2. 如何判断对象是否存在循环引用(重要)?

3. 出现循环引用的几种情况

常见的循环引用有两种情况,对象之间相互引用对象的属性引用对象本身

3.1 对象之间相互引用

代码语言:javascript
复制
let obj1 = { name: '前端胖头鱼1' }
let obj2 = { name: '前端胖头鱼2' }
// 对象1的属性引用了对象2
obj1.obj = obj2
// 对象2的属性引用了对象1
obj2.obj = obj1

3.2 对象的属性引用对象本身

1. 直接引用最外层的对象

代码语言:javascript
复制
let obj = { name: '前端胖头鱼1' }
// 对象的属性引用了对象本身
obj.child = obj

2. 引用对象的部分属性

代码语言:javascript
复制

let obj = {
  name: '前端胖头鱼',
  child: {}
}

obj.child.obj = obj.child

4. 如何判断对象是否存在循环引用?

根据出现循环引用可能有的几种情况,我们可以试着写出下列代码

4.1 源码实现

代码语言:javascript
复制
const isCyclic = (obj) => {
  // 使用Set数据类型来存储已经检测过的对象
  let stackSet = new Set()
  let detected = false

  const detect = (obj) => {
    // 不是对象类型的话,可以直接跳过
    if (obj && typeof obj != 'object') {
      return
    }
    // 当要检查的对象已经存在于stackSet中时,表示存在循环引用
    if (stackSet.has(obj)) {
      return detected = true
    }
    // 将当前obj存如stackSet
    stackSet.add(obj)

    for (let key in obj) {
      // 对obj下的属性进行挨个检测
      if (obj.hasOwnProperty(key)) {
        detect(obj[key])
      }
    }
    // 平级检测完成之后,将当前对象删除,防止误判
    /*
      例如:对象的属性指向同一引用,如果不删除的话,会被认为是循环引用
      let tempObj = {
        name: '前端胖头鱼'
      }
      let obj4 = {
        obj1: tempObj,
        obj2: tempObj
      }
    */
    stackSet.delete(obj)
  }

  detect(obj)

  return detected
}


4.2 测试一把

代码语言:javascript
复制
// 1. 对象之间相互引用

let obj1 = { name: '前端胖头鱼1' }
let obj2 = { name: '前端胖头鱼2' }
// 对象1的属性引用了对象2
obj1.obj = obj2
// 对象2的属性引用了对象1
obj2.obj = obj1

console.log(isCyclic(obj1)) // true
console.log(isCyclic(obj2)) // true

// 2. 对象的属性引用了对象本身

let obj = { name: '前端胖头鱼1' }
// 对象的属性引用了对象本身
obj.child = obj

console.log(isCyclic(obj)) // true

// 3. 对象的属性引用部分属性

let obj3 = {
  name: '前端胖头鱼',
  child: {}
}

obj3.child.obj = obj3.child

console.log(isCyclic(obj3)) // true

// 4. 对象的属性指向同一引用
let tempObj = {
  name: '前端胖头鱼'
}
let obj4 = {
  obj1: tempObj,
  obj2: tempObj
}

console.log(isCyclic(obj4)) // false

// 5. 其他数据类型

console.log(isCyclic(1)) // false
console.log(isCyclic('前端胖头鱼')) // false
console.log(isCyclic(false)) // false
console.log(isCyclic(null)) // false
console.log(isCyclic(undefined)) // false
console.log(isCyclic([])) // false
console.log(isCyclic(Symbol('前端胖头鱼'))) // false

5. 结尾

一个非常小的知识点,感谢大家阅读。如果有兴趣可以更进一步探索一些有意思的话题:

比如:

  1. 如何在JSON.stringify中输出有循环引用的对象。
  2. JS的垃圾回收机制中是如何处理循环引用的等等。
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端胖头鱼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 手写62+方法学习JavaScript底层原理
  • 2. 不得不说的循环引用
  • 3. 出现循环引用的几种情况
    • 3.1 对象之间相互引用
      • 3.2 对象的属性引用对象本身
      • 4. 如何判断对象是否存在循环引用?
        • 4.1 源码实现
          • 4.2 测试一把
          • 5. 结尾
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档