头图

听说你的对象有个”环“?怎么发现的呢?

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

判断一个对象是否存在循环引用已收录至 手写各种源码实现,也可以直接点击isCyclic快速查看,目前已有62+手写实现,欢迎一起来学习喔。

image.png

2. 不得不说的循环引用

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

WechatIMG183.jpeg

image.png

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

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

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

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

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

3.1 对象之间相互引用

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

image.png

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

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

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

image.png
2. 引用对象的部分属性


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

obj.child.obj = obj.child

image.png

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

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

4.1 源码实现

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 测试一把

// 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的垃圾回收机制中是如何处理循环引用的等等。

3.6k 声望
6.1k 粉丝
0 条评论
推荐阅读
面试官:Vue3响应式系统都不会写,还敢说精通?
也许你我素未谋面,但很可能相见恨晚,我是前端胖头鱼前言都说今年是最惨工作年,大厂裁员,小厂跟风,简历投了几百封回信的寥寥无几,金三银四怕是成了铜三铁四,冷冷清清,凄凄惨惨。但是今天的主角,小帅同学...

前端胖头鱼5阅读 4.3k评论 2

封面图
Vue微信公众号开发踩坑记录
JS-SDK需要向服务端获取签名,且获取签名中需要的参数包括所在页面的url,但由于单页应用的路由特殊,其中涉及到iOS和android微信客户端浏览器内核的差异性导致的兼容问题

imwty132阅读 67.7k评论 81

手把手教你写一份优质的前端技术简历
不知不觉一年一度的秋招又来了,你收获了哪些大厂的面试邀约,又拿了多少offer呢?你身边是不是有挺多人技术比你差,但是却拿到了很多大厂的offer呢?其实,要想面试拿offer,首先要过得了简历那一关。如果一份简...

tonychen152阅读 17.8k评论 5

封面图
正则表达式实例
收集在业务中经常使用的正则表达式实例,方便以后进行查找,减少工作量。常用正则表达式实例1. 校验基本日期格式 {代码...} {代码...} 2. 校验密码强度密码的强度必须是包含大小写字母和数字的组合,不能使用特殊...

寒青56阅读 8.5k评论 11

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy48阅读 7.1k评论 12

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木75阅读 7.1k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs42阅读 6.8k评论 12

封面图
3.6k 声望
6.1k 粉丝
宣传栏