InterviewHubPRO
Section Overview
Q514

Question 514 of 521

Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

99%
JavaScript Internals (521 Qs)•Part 8: Modern JavaScript APIs, WeakRef, Proxy & Performance (464 - 521)

What are the different ways to handle circular references in JSON?

Circular references occur when an object references itself directly or indirectly, causing JSON.stringify() to throw an error.

Problem:

javascript
 const obj = { name: 'John' };
 obj.self = obj; // Circular reference

 // JSON.stringify(obj); // Throws: TypeError: Converting circular structure to JSON

Solution 1: Custom replacer function:

javascript
 function stringifyWithCircular(obj) {
   const seen = new WeakSet();
   return JSON.stringify(obj, (key, value) => {
     if (typeof value === 'object' && value !== null) {
       if (seen.has(value)) {
         return '[Circular]';
       }
       seen.add(value);
     }
     return value;
   });
 }

 const obj = { name: 'John' };
 obj.self = obj;
 console.log(stringifyWithCircular(obj));
 // {"name":"John","self":"[Circular]"}

Solution 2: flatted library (preserves structure):

javascript
 import { stringify, parse } from 'flatted';

 const obj = { name: 'John' };
 obj.self = obj;

 const serialized = stringify(obj);
 const deserialized = parse(serialized);
 console.log(deserialized.self === deserialized); // true

Solution 3: Manual tracking with paths:

javascript
 function safeStringify(obj, space) {
   const seen = new Map();
   let index = 0;

   return JSON.stringify(obj, function(key, value) {
     if (typeof value === 'object' && value !== null) {
       if (seen.has(value)) {
         return `[Circular:${seen.get(value)}]`;
       }
       seen.set(value, index++);
     }
     return value;
   }, space);
 }

Solution 4: Remove circular references:

javascript
 function removeCircular(obj) {
   const seen = new WeakSet();

   function detect(obj) {
     if (typeof obj === 'object' && obj !== null) {
       if (seen.has(obj)) {
         return undefined;
       }
       seen.add(obj);

       if (Array.isArray(obj)) {
         return obj.map(detect).filter(x => x !== undefined);
       }

       const cleaned = {};
       for (const [key, value] of Object.entries(obj)) {
         const cleaned value = detect(value);
         if (cleanedValue !== undefined) {
           cleaned[key] = cleanedValue;
         }
       }
       return cleaned;
     }
     return obj;
   }

   return detect(obj);
 }

 const obj = { name: 'John', child: { name: 'Jane' } };
 obj.child.parent = obj;
 const clean = removeCircular(obj);
 console.log(JSON.stringify(clean));

Solution 5: Using toJSON method:

javascript
 class Node {
   constructor(name) {
     this.name = name;
     this.parent = null;
     this.children = [];
   }

   toJSON() {
     return {
       name: this.name,
       children: this.children,
       // Exclude parent to avoid circular reference
     };
   }
 }

 const root = new Node('root');
 const child = new Node('child');
 root.children.push(child);
 child.parent = root;

 console.log(JSON.stringify(root)); // Works fine