本文翻译自:How can I print a circular structure in a JSON-like format?
I have a big object I want to convert to JSON and send. 我有一个大对象,想要转换为JSON并发送。 However it has circular structure. 但是它具有圆形结构。 I want to toss whatever circular references exist and send whatever can be stringified. 我想抛弃任何存在的循环引用,并发送任何可以字符串化的内容。 How do I do that? 我怎么做?
Thanks. 谢谢。
var obj = {
a: "foo",
b: obj
}
I want to stringify obj into: 我想将obj字符串化为:
{"a":"foo"}
#1楼
参考:https://stackoom.com/question/mk10/如何以类似JSON的格式打印圆形结构
#2楼
Use JSON.stringify
with a custom replacer. 将JSON.stringify
与自定义JSON.stringify
一起使用。 For example: 例如:
// Demo: Circular reference
var circ = {};
circ.circ = circ;
// Note: cache should not be re-used by repeated calls to JSON.stringify.
var cache = [];
JSON.stringify(circ, function(key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// Duplicate reference found, discard key
return;
}
// Store value in our collection
cache.push(value);
}
return value;
});
cache = null; // Enable garbage collection
The replacer in this example is not 100% correct (depending on your definition of "duplicate"). 在此示例中,替换器并非100%正确(取决于您对“重复”的定义)。 In the following case, a value is discarded: 在以下情况下,将丢弃一个值:
var a = {b:1}
var o = {};
o.one = a;
o.two = a;
// one and two point to the same object, but two is discarded:
JSON.stringify(o, ...);
But the concept stands: Use a custom replacer, and keep track of the parsed object values. 但是概念仍然存在:使用自定义替换器,并跟踪已解析的对象值。
#3楼
Use the JSON.stringify method with a replacer. 将JSON.stringify方法与替换器一起使用。 Read this documentation for more information. 阅读此文档以获取更多信息。 http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx http://msdn.microsoft.com/zh-cn/library/cc836459%28v=vs.94%29.aspx
var obj = {
a: "foo",
b: obj
}
var replacement = {"b":undefined};
alert(JSON.stringify(obj,replacement));
Figure out a way to populate the replacement array with cyclic references. 找出一种使用循环引用填充替换数组的方法。 You can use the typeof method to find if an the property is of type 'object' ( reference ) and an exact equality check ( === ) to verify circular reference. 您可以使用typeof方法查找属性是否为'object'类型(引用),并使用精确相等性检查(===)来验证循环引用。
#4楼
For future googlers searching for a solution to this problem when you don't know the keys of all circular references, you could use a wrapper around the JSON.stringify function to rule out circular references. 对于将来的Google员工,当您不知道所有循环引用的键时都在寻找解决方案,可以使用JSON.stringify函数周围的包装器来排除循环引用。 See an example script at https://gist.github.com/4653128 . 请参阅https://gist.github.com/4653128上的示例脚本。
The solution essentially boils down to keeping a reference to previously printed objects in an array, and checking that in a replacer function before returning a value. 解决方案本质上可以归结为保留对数组中先前打印的对象的引用,并在返回值之前在替换函数中进行检查。 It's more constrictive than only ruling out circular references, because it also rules out ever printing an object twice, one of the side affects of which is to avoid circular references. 它比仅排除循环引用更为严格,因为它还排除了两次打印对象的副作用,其中之一是避免使用循环引用。
Example wrapper: 包装器示例:
function stringifyOnce(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if(printedObjIndex && typeof(value)=="object"){
return "(see " + value.constructor.name.toLowerCase() + " with key " + printedObjectKeys[printedObjIndex] + ")";
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
}
#5楼
I really liked Trindaz's solution - more verbose, however it had some bugs. 我真的很喜欢Trindaz的解决方案-更详细,但是有一些错误。 I fixed them for whoever likes it too. 我为喜欢的人固定了它们。
Plus, I added a length limit on my cache objects. 另外,我在缓存对象上增加了长度限制。
If the object I am printing is really big - I mean infinitely big - I want to limit my algorithm. 如果我要打印的对象真的很大-我的意思是无限大-我想限制我的算法。
JSON.stringifyOnce = function(obj, replacer, indent){
var printedObjects = [];
var printedObjectKeys = [];
function printOnceReplacer(key, value){
if ( printedObjects.length > 2000){ // browsers will not print more than 20K, I don't see the point to allow 2K.. algorithm will not be fast anyway if we have too many objects
return 'object too long';
}
var printedObjIndex = false;
printedObjects.forEach(function(obj, index){
if(obj===value){
printedObjIndex = index;
}
});
if ( key == ''){ //root element
printedObjects.push(obj);
printedObjectKeys.push("root");
return value;
}
else if(printedObjIndex+"" != "false" && typeof(value)=="object"){
if ( printedObjectKeys[printedObjIndex] == "root"){
return "(pointer to root)";
}else{
return "(see " + ((!!value && !!value.constructor) ? value.constructor.name.toLowerCase() : typeof(value)) + " with key " + printedObjectKeys[printedObjIndex] + ")";
}
}else{
var qualifiedKey = key || "(empty key)";
printedObjects.push(value);
printedObjectKeys.push(qualifiedKey);
if(replacer){
return replacer(key, value);
}else{
return value;
}
}
}
return JSON.stringify(obj, printOnceReplacer, indent);
};
#6楼
In Node.js, you can use util.inspect(object) . 在Node.js中,可以使用util.inspect(object) 。 It automatically replaces circular links with "[Circular]". 它会自动将圆形链接替换为“ [Circular]”。
Albeit being built-in (no installation is required) , you must import it 尽管是内置的(无需安装) ,但必须将其导入
import * as util from 'util' // has no default export
import { inspect } from 'util' // or directly
// or
var util = require('util')
To use it, simply call
要使用它,只需调用
inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])
Also be aware that you can pass options object to inspect (see link above) 另外请注意,您可以通过options对象进行检查(请参见上面的链接)
inspect(myObject[, options: {showHidden, depth, colors, showProxy, ...moreOptions}])
Please, read and give kudos to commenters below... 请阅读下面的评论并将其赞扬...