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

判断一个对象是否存在循环援用已收录至 手写各种源码实现,也能够间接点击isCyclic疾速查看,目前已有62+手写实现,欢送一起来学习喔。

2. 不得不说的循环援用

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

在旧的浏览器中循环援用是造成内存透露的一个起因,当然随着垃圾收集算法的改良,当初能够很好地解决循环援用,这不再是一个问题。

只须要3分钟工夫,本文会您一起学习

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

3. 呈现循环援用的几种状况

常见的循环援用有两种状况,对象之间互相援用对象的属性援用对象自身

3.1 对象之间互相援用

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

3.2 对象的属性援用对象自身

1. 间接援用最外层的对象

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


2. 援用对象的局部属性

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

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的属性援用了对象2obj1.obj = obj2// 对象2的属性援用了对象1obj2.obj = obj1console.log(isCyclic(obj1)) // trueconsole.log(isCyclic(obj2)) // true// 2. 对象的属性援用了对象自身let obj = { name: '前端胖头鱼1' }// 对象的属性援用了对象自身obj.child = objconsole.log(isCyclic(obj)) // true// 3. 对象的属性援用局部属性let obj3 = {  name: '前端胖头鱼',  child: {}}obj3.child.obj = obj3.childconsole.log(isCyclic(obj3)) // true// 4. 对象的属性指向同一援用let tempObj = {  name: '前端胖头鱼'}let obj4 = {  obj1: tempObj,  obj2: tempObj}console.log(isCyclic(obj4)) // false// 5. 其余数据类型console.log(isCyclic(1)) // falseconsole.log(isCyclic('前端胖头鱼')) // falseconsole.log(isCyclic(false)) // falseconsole.log(isCyclic(null)) // falseconsole.log(isCyclic(undefined)) // falseconsole.log(isCyclic([])) // falseconsole.log(isCyclic(Symbol('前端胖头鱼'))) // false

5. 结尾

一个十分小的知识点,感激大家浏览。如果有趣味能够更进一步摸索一些有意思的话题:

比方:

  1. 如何在JSON.stringify中输入有循环援用的对象。
  2. JS的垃圾回收机制中是如何解决循环援用的等等。