鉴于我在一个大型 JavaScript 对象中有一个循环引用
我尝试 JSON.stringify(problematicObject)
浏览器抛出
“类型错误:将圆形结构转换为 JSON”
(这是预期的)
那我想找到这个循环引用的原因,最好使用Chrome开发者工具?这可能吗?如何在大对象中查找和修复循环引用?
鉴于我在一个大型 JavaScript 对象中有一个循环引用
我尝试 JSON.stringify(problematicObject)
浏览器抛出
“类型错误:将圆形结构转换为 JSON”
(这是预期的)
那我想找到这个循环引用的原因,最好使用Chrome开发者工具?这可能吗?如何在大对象中查找和修复循环引用?
摘自http://blog.vjeux.com/2011/javascript/cyclic-object-detection.html。添加了一行以检测循环的位置。将其粘贴到 Chrome 开发工具中:
function isCyclic (obj) {
var seenObjects = [];
function detect (obj) {
if (obj && typeof obj === 'object') {
if (seenObjects.indexOf(obj) !== -1) {
return true;
}
seenObjects.push(obj);
for (var key in obj) {
if (obj.hasOwnProperty(key) && detect(obj[key])) {
console.log(obj, 'cycle at ' + key);
return true;
}
}
}
return false;
}
return detect(obj);
}
这是测试:
> a = {}
> b = {}
> a.b = b; b.a = a;
> isCyclic(a)
Object {a: Object}
"cycle at a"
Object {b: Object}
"cycle at b"
true
@tmack 的答案绝对是我发现这个问题时所寻找的!
不幸的是,它返回许多误报 - 如果对象在 JSON 中复制,则返回 true,这与循环性不同。循环意味着一个对象是它自己的孩子,例如
obj.key1.key2.[...].keyX === obj
我修改了原始答案,这对我有用:
function isCyclic(obj) {
var keys = [];
var stack = [];
var stackSet = new Set();
var detected = false;
function detect(obj, key) {
if (obj && typeof obj != 'object') { return; }
if (stackSet.has(obj)) { // it's cyclic! Print the object and its locations.
var oldindex = stack.indexOf(obj);
var l1 = keys.join('.') + '.' + key;
var l2 = keys.slice(0, oldindex + 1).join('.');
console.log('CIRCULAR: ' + l1 + ' = ' + l2 + ' = ' + obj);
console.log(obj);
detected = true;
return;
}
keys.push(key);
stack.push(obj);
stackSet.add(obj);
for (var k in obj) { //dive on the object's children
if (Object.prototype.hasOwnProperty.call(obj, k)) { detect(obj[k], k); }
}
keys.pop();
stack.pop();
stackSet.delete(obj);
return;
}
detect(obj, 'obj');
return detected;
}
下面是一些非常简单的测试:
var root = {}
var leaf = {'isleaf':true};
var cycle2 = {l:leaf};
var cycle1 = {c2: cycle2, l:leaf};
cycle2.c1 = cycle1
root.leaf = leaf
isCyclic(cycle1); // returns true, logs "CIRCULAR: obj.c2.c1 = obj"
isCyclic(cycle2); // returns true, logs "CIRCULAR: obj.c1.c2 = obj"
isCyclic(leaf); // returns false
isCyclic(root); // returns false
以下是 MDNJSON.stringify()
在循环对象上使用时检测和修复循环引用的方法:https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value:
在如下所示的圆形结构中
var circularReference = {otherData: 123};
circularReference.myself = circularReference;
JSON.stringify()
将失败:
JSON.stringify(circularReference);
// TypeError: cyclic object value
要序列化循环引用,您可以使用支持它们的库(例如cycle.js)或自己实现解决方案,这将需要通过可序列化值查找和替换(或删除)循环引用。
下面的代码片段说明了如何使用的替换参数来查找和过滤(从而导致数据丢失)循环引用:
JSON.stringify()
const getCircularReplacer = () => {
const seen = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
JSON.stringify(circularReference, getCircularReplacer());
// {"otherData":123}
这是对@Trey Mack和@Freddie Nfbnm在typeof obj != 'object'
条件下回答的修复。相反,它应该测试obj
值是否不是对象的实例,以便在检查具有对象熟悉度的值时它也可以工作(例如,函数和符号(符号不是对象的实例,但仍然被寻址,顺便说一句))。
我将此作为答案发布,因为我还无法在此 StackExchange 帐户中发表评论。
PS.:请随时要求我删除此答案。
function isCyclic(obj) {
var keys = [];
var stack = [];
var stackSet = new Set();
var detected = false;
function detect(obj, key) {
if (!(obj instanceof Object)) { return; } // Now works with other
// kinds of object.
if (stackSet.has(obj)) { // it's cyclic! Print the object and its locations.
var oldindex = stack.indexOf(obj);
var l1 = keys.join('.') + '.' + key;
var l2 = keys.slice(0, oldindex + 1).join('.');
console.log('CIRCULAR: ' + l1 + ' = ' + l2 + ' = ' + obj);
console.log(obj);
detected = true;
return;
}
keys.push(key);
stack.push(obj);
stackSet.add(obj);
for (var k in obj) { //dive on the object's children
if (obj.hasOwnProperty(k)) { detect(obj[k], k); }
}
keys.pop();
stack.pop();
stackSet.delete(obj);
return;
}
detect(obj, 'obj');
return detected;
}
您也可以JSON.stringify
与try/catch 一起使用
function hasCircularDependency(obj)
{
try
{
JSON.stringify(obj);
}
catch(e)
{
return e.includes("Converting circular structure to JSON");
}
return false;
}
演示