什么情况下会出现循环引用?
我个人的理解是,如果一个对象的值等于父级(祖父级,曾祖父级....),则说明是循环引用了。来看下面一个例子:
用上面代码来解释我定义的循环引用:a.info
的值是a
,而a
恰好是a.info
的父级,所以这里就是循环引用了。
如何处理循环引用对象呢?
首先,循环引用对象本来没有什么问题,序列化的时候才会发生问题,比如调用JSON.stringify()
对该类对象进行序列化,就会报错: Converting circular structure to JSON.
,而序列化需求很常见,比如发起一个ajax请求提交一个对象就需要对对象进行序列化。
针对上面这样的问题,可以通过JSON
扩展包的var c = JSON.decycle(a)
和var a = JSON.retrocycle(c)
来处理。这里就不做过多的解释了。
重点来了
手动写一个方法来判断对象是否存在循环引用,来看下边一段代码:
function cycle(obj, parent) {
//表示调用的父级数组
var parentArr = parent || [obj];
for (var i in obj) {
if (typeof obj[i] === "object") {
//判断是否有循环引用
parentArr.forEach((pObj) => {
if (pObj === obj[i]) {
obj[i] = "[cycle]"
}
});
cycle(obj[i], [...parentArr, obj[i]])
}
}
return obj;
}
上面函数中,parentArr
为取值的所有父级的一个集合;
循环对象,如果对象是一个object
类型的,先循环数组parentArr
,判断该值是否是parentArr
中的引用,如果是,则存在循环引用,并把循环引用值设置成特殊标识"[cycle]"
,接着再进行递归调用,并且把对应取值链上的父级集合传递下去。
测试:
var a = {
b:{
c:{}
}
};
a.b.c.d = a;
console.log(cycle(a));
结果如下:
可以看到,a.b.c.d
原本是一个循环引用的a
值,经过处理以后,变成了循环引用的标识;
内容就这么多,有错误希望大佬可以多多指点,交流才能进步!