Stringify (Convert to JSON) a JavaScript Object with Circular Reference

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



Leave a reply



Submit