// 思路
// 递归时用parent数组记录遍历过的历史对象
// 与每层的对象属性对比 找是否存在循环引用
function fn(obj, parent) {
let list = parent || [obj]
for (let key in obj) {
if (typeof obj[key] === 'object') {
// 取出当前层obj中每个属性 与 parent中对比
for (let val of list) {
if (val === obj[key]) {
// 递归出口 引用地址相同 返回结果
return true
}
}
// 没找到继续往下一层递归
// 将当前层的obj[key] 与 历史parent合并成新的parent传入下一层
let result = fn(obj[key], [...list, obj[key]])
// 递归返回的结果为true 则 不继续进行遍历 而是返回结果
if (result) return true
}
}
// 遍历完仍然没有返回true 说明没有循环引用
return false
}
// 验证
let a = 1
let b = { a }
let c = { b }
let o = { d: { a: 3 }, c }
o.c.b.aa = a
console.log(fn(o)) // false
console