Stringify (convert to JSON) a JavaScript object with circular reference
Circular structure error occurs when you have a property of the object which is the object itself directly (a -> a
) or indirectly (a -> b -> a
).
To avoid the error message, tell JSON.stringify what to do when it encounters a circular reference.
For example, if you have a person pointing to another person ("parent"), which may (or may not) point to the original person, do the following:
JSON.stringify( that.person, function( key, value) {
if( key == 'parent') { return value.id;}
else {return value;}
})
The second parameter to stringify
is a filter function. Here it simply converts the referred object to its ID, but you are free to do whatever you like to break the circular reference.
You can test the above code with the following:
function Person( params) {
this.id = params['id'];
this.name = params['name'];
this.father = null;
this.fingers = [];
// etc.
}
var me = new Person({ id: 1, name: 'Luke'});
var him = new Person( { id:2, name: 'Darth Vader'});
me.father = him;
JSON.stringify(me); // so far so good
him.father = me; // time travel assumed :-)
JSON.stringify(me); // "TypeError: Converting circular structure to JSON"
// But this should do the job:
JSON.stringify(me, function( key, value) {
if(key == 'father') {
return value.id;
} else {
return value;
};
});
BTW, I'd choose a different attribute name to "parent
" since it is a reserved word in many languages (and in DOM). This tends to cause confusion down the road...
How can I print a circular structure in a JSON-like format?
Use JSON.stringify
with a custom replacer. 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, (key, value) => {
if (typeof value === 'object' && value !== null) {
// Duplicate reference found, discard key
if (cache.includes(value)) 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"). 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.
As a utility function written in es6:
// safely handles circular references
JSON.safeStringify = (obj, indent = 2) => {
let cache = [];
const retVal = JSON.stringify(
obj,
(key, value) =>
typeof value === "object" && value !== null
? cache.includes(value)
? undefined // Duplicate reference found, discard key
: cache.push(value) && value // Store value in our collection
: value,
indent
);
cache = null;
return retVal;
};
// Example:
console.log('options', JSON.safeStringify(options))
Converting circular structure to JSON at JSON.stringify ()
A circular structure is a structure which references itself as a value. JSON.stringify
does not support such structures, since it would result in an infinitely-long string.
What you need is a deep cloning function which does not use JSON.stringify
. Such implementation can be found here.
How to keep circular reference, when stringifying JS object to JSON
Have you tried a library that allows circular references?
One good one is DOJO.
https://www.sitepen.com/blog/2008/06/17/json-referencing-in-dojo/
From its instructions:
var obj = {};
obj.me = obj;
var jsonWithCircularRef = dojox.json.ref.toJson(obj);
using toJSON() to filter out circular reference from array of objects before writing to .json file
There are two main ways to solve this issue:
One is to use cycle.js which introduces two functions, JSON.decycle()
and JSON.retrocycle()
, which makes it possible to encode and decode cyclical structures and dags into an extended and retrocompatible JSON format.
Or you can implement your own solution which will require finding and replacing (or removing) the cyclic references by serializable values.
The snippet below illustrates how to find and filter (thus causing data loss) a cyclic reference by using the replacer
parameter of JSON.stringify()
:
var circularReference = {otherData: 123};
circularReference.myself = circularReference;
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());
Please refer here for more information.
Chrome sendrequest error: TypeError: Converting circular structure to JSON
It means that the object you pass in the request (I guess it is pagedoc
) has a circular reference, something like:
var a = {};
a.b = a;
JSON.stringify
cannot convert structures like this.
N.B.: This would be the case with DOM nodes, which have circular references, even if they are not attached to the DOM tree. Each node has an ownerDocument
which refers to document
in most cases. document
has a reference to the DOM tree at least through document.body
and document.body.ownerDocument
refers back to document
again, which is only one of multiple circular references in the DOM tree.
Related Topics
How to Convert the "Arguments" Object to an Array in JavaScript
How to Call 3 Functions in Order to Execute Them One After the Other
Safari 3Rd Party Cookie Iframe Trick No Longer Working
What's the Difference Between Window.Location= and Window.Location.Replace()
(![]+[])[+[]]... Explain Why This Works
Angularjs - Any Way for $Http.Post to Send Request Parameters Instead of JSON
How to Create Multidimensional Array
How to Create a Function from a String with JavaScript
How to Convert Date to Timestamp
Check If Event Exists on Element
Detecting When a Div's Height Changes Using Jquery
Getting Scroll Bar Width Using JavaScript
JavaScript Loop Through JSON Array
What Is the Order of Execution in JavaScript Promises