乐趣区

关于前端:听说你的对象有个环怎么发现的呢

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

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

2. 不得不说的循环援用

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

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

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

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

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

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

3.1 对象之间互相援用

let obj1 = {name: '前端胖头鱼 1'}
let obj2 = {name: '前端胖头鱼 2'}
// 对象 1 的属性援用了对象 2
obj1.obj = obj2
// 对象 2 的属性援用了对象 1
obj2.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 的属性援用了对象 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 的垃圾回收机制中是如何解决循环援用的等等。
退出移动版