Explain Codes LogoExplain Codes Logo

How can I print a circular structure in a JSON-like format?

javascript
circular-structure
json-format
node-js
Nikita BarsukovbyNikita Barsukov·Oct 7, 2024
TLDR

JSON.stringify has a built-in mechanism for dealing with circular references, through the addition of a replacer function. By using a WeakSet to keep track of each object, you can effectively replace each circular reference with "[Circular]":

// Time to keep an eye on any circular suspects! const circularReplacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { // Busted! You're going in circles mate. return "[Circular]"; } seen.add(value); } return value; }; }; const obj = { self: null }; obj.self = obj; // Now that's a loop you won't easily escape... // "[Circular]" or bust. console.log(JSON.stringify(obj, circularReplacer())); // Outputs: '{"self":"[Circular]"}'

This nifty solution handcuffs circularity effortlessly, transforming the convoluted object into a neat, JSON-friendly string.

Node.js built-in solution

Those who prefer smooth sailing with Node.js can simply deploy its built-in utility util.inspect which makes handling circular structures a breeze:

// Here comes Node.js in its shining armour! const util = require('util'); const obj = { self: null }; obj.self = obj; // That loop is back again, but not for long... // Utility to the rescue! console.log(util.inspect(obj)) // Outputs: '{ self: [Circular] }'

It comes bundled with a parcel of heartening benefits, including additional options such as showHidden, depth, and colors, to customize the process in line with your debugger's desires.

Heavy-weight contender: handling complex objects

When your objects look like a beast with an insatiable appetite, a memory-friendly strategy becomes an imperative. Limiting the length of cached objects or managing garbage collection post-caching could help tame your object's wild appetite for memory.

Smart custom serializations

In more particular cases, such as handling repeated values, or adding pointers to the root of the structure, you might find yourself tailoring utility functions. Not only will these saviors help uphold data integrity during serialization, they also serve as guiding stars leading the way through the object structure universe.

Deal with circular structure like a Pro

Let's make your ride smooth in the wild world of JSON with:

🎢 Imagine you're the caretaker of a theme park, and you're dealing with a Maze of Mirror:

  • Before you intervene, the guests lose their way amidst the endless reflections and can't get out.
// Ah, the endless hallways of mirrors... Quite a mind-bender! const circularReference = { other: null }; circularReference.other = circularReference;
  • With your magic wand (i.e., our circular replacer), all of a sudden, the endlessly tunneling maze becomes a clear path with signs!
// And voilà, the path is clear. No more losing one's way! { "value": "I am a guest", "other": "[Circular ~]" }

Third-party libraries to the rescue

If you prefer to step aside and let libraries do the heavy lifting, use flatted. As a successor of circular-json, it is equipped with the prowess to tame circular structures:

npm install flatted
// Why take up arms when you have got hired muscle? const flatted = require('flatted'); const obj = { self: null }; obj.self = obj; console.log(flatted.stringify(obj)); // Outputs: '["{self:[0]}"]'

This nifty library saves space by serializing objects into a simplified array format, making the output concise and easy on the eyes.

Go beyond with structured cloning

If your creative flow isn’t bound by the confines of JSON, consider the HTML Structured Clone Algorithm, designed to handle circular references with grace and without any need for string semantics.