Circular references can create serious problems in JavaScript β from infinite recursions to JSON.stringify errors. Hereβs how to remove cycles both structurally and during serialization using idiomatic, memory-safe JavaScript.
WeakSetRemove circular references in-place from object graphs (e.g., linked lists, trees, graphs).
A recursive traversal tracks visited objects using a WeakSet. If a reference is encountered again, it is removed.
const removeCycle = (obj) => { const set = new WeakSet([obj]); (function iterate(current) { for (let key in current) { if (!current.hasOwnProperty(key)) continue; const val = current[key]; if (typeof val === 'object' && val !== null) { if (set.has(val)) { delete current[key]; // Cycle detected, remove } else { set.add(val); iterate(val); // Recurse deeper } } } })(obj); };
function List(val) { this.val = val; this.next = null; } const item1 = new List(10); const item2 = new List(20); const item3 = new List(30); item1.next = item2; item2.next = item3; item3.next = item1; // Circular reference removeCycle(item1); console.log(item1); // { val: 10, next: { val: 20, next: { val: 30 } } }
JSON.stringify() with ReplacerRemove cycles on-the-fly during serialization to JSON. Useful when you don't want to mutate the original object.
JSON.stringify accepts a replacer function. You can use a WeakSet inside this replacer to track seen objects and return undefined for repeats (i.e., remove cycles).
const getCircularReplacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === 'object' && value !== null) { if (seen.has(value)) return; // Omit cyclic reference seen.add(value); } return value; }; };
console.log(JSON.stringify(item1, getCircularReplacer(), 2));
{ "val": 10, "next": { "val": 20, "next": { "val": 30 } } }
| Use Case | Use removeCycle() | Use getCircularReplacer() |
|---|---|---|
| Mutate structure and clean cycles | β Yes | β No (non-destructive) |
| Safe JSON serialization | β No | β Yes |
| Need to traverse or clone afterward | β Yes | β No (only during serialization) |
| Want GC-safe memory tracking | β Uses WeakSet | β Uses WeakSet |
WeakSetis perfect for tracking object identity in cyclic graphs, without interfering with garbage collection.
WeakSet to clean up in-memory object graphs.JSON.stringify with a custom replacer to safely serialize cyclic structures on-demand.These patterns are standard in tools like fast-safe-stringify, circular-json, or serializers for distributed systems and state management frameworks.
Test your understanding with 3 quick questions