简体   繁体   中英

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

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

Here's a solution that:

  • removes cycles only (and not all duplicate object references, as do most of the solutions posted here so far),
  • is not unnecessarily verbose,
  • is fast,
  • does not require any library dependency.
function replaceCycles(obj, replacement = undefined, seen = new WeakSet()) {
  if (typeof obj === 'object')
    if (seen.has(obj))
      return replacement 
    else {
      seen.add(obj)
      const newObj = {}
      for (const key in obj)
        newObj[key] = replaceCycles(obj[key], replacement, seen)
      seen.delete(obj)
      return newObj
    }
  else
    return obj
}

Usage:

const a = {
  b: 'v1',
  c: {
    d: 'v2'
  }
}

a.e = a.c
a.c.f = a.c

console.log(JSON.stringify(replaceCycles(a, '[CYCLE]')))

Output:

"{'b':'v1','c':{'d':'v2','f':'[CYCLE]'},'e':{'d':'v2','f':'[CYCLE]'}}"

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

In my solution, if you run into a cycle, it doesn't just say "cycle" (or nothing), it says something like foo: see object#42 above, and to see where foo points to you can scroll up and search for object#42 (each object, when it starts, says object#xxx with some integer xxx)

Snippet:

 (function(){ "use strict"; var ignore = [Boolean, Date, Number, RegExp, String]; function primitive(item){ if (typeof item === 'object'){ if (item === null) { return true; } for (var i=0; i<ignore.length; i++){ if (item instanceof ignore[i]) { return true; } } return false; } else { return true; } } function infant(value){ return Array.isArray(value) ? [] : {}; } JSON.decycleIntoForest = function decycleIntoForest(object, replacer) { if (typeof replacer !== 'function'){ replacer = function(x){ return x; } } object = replacer(object); if (primitive(object)) return object; var objects = [object]; var forest = [infant(object)]; var bucket = new WeakMap(); // bucket = inverse of objects bucket.set(object, 0); // ie, map object to index in array function addToBucket(obj){ var result = objects.length; objects.push(obj); bucket.set(obj, result); return result; } function isInBucket(obj){ return bucket.has(obj); // objects[bucket.get(obj)] === obj, iff true is returned } function processNode(source, target){ Object.keys(source).forEach(function(key){ var value = replacer(source[key]); if (primitive(value)){ target[key] = {value: value}; } else { var ptr; if (isInBucket(value)){ ptr = bucket.get(value); } else { ptr = addToBucket(value); var newTree = infant(value); forest.push(newTree); processNode(value, newTree); } target[key] = {pointer: ptr}; } }); } processNode(object, forest[0]); return forest; }; })(); the = document.getElementById('the'); function consoleLog(toBeLogged){ the.textContent = the.textContent + '\\n' + toBeLogged; } function show(root){ var cycleFree = JSON.decycleIntoForest(root); var shown = cycleFree.map(function(tree, idx){ return false; }); var indentIncrement = 4; function showItem(nodeSlot, indent, label){ leadingSpaces = ' '.repeat(indent); leadingSpacesPlus = ' '.repeat(indent + indentIncrement); if (shown[nodeSlot]){ consoleLog(leadingSpaces + label + ' ... see above (object #' + nodeSlot + ')'); } else { consoleLog(leadingSpaces + label + ' object#' + nodeSlot); var tree = cycleFree[nodeSlot]; shown[nodeSlot] = true; Object.keys(tree).forEach(function(key){ var entry = tree[key]; if ('value' in entry){ consoleLog(leadingSpacesPlus + key + ": " + entry.value); } else { if ('pointer' in entry){ showItem(entry.pointer, indent+indentIncrement, key); } } }); } } showItem(0, 0, 'root'); } cities4d = { Europe:{ north:[ {name:"Stockholm", population:1000000, temp:6}, {name:"Helsinki", population:650000, temp:7.6} ], south:[ {name:"Madrid", population:3200000, temp:15}, {name:"Rome", population:4300000, temp:15} ] }, America:{ north:[ {name:"San Francisco", population:900000, temp:14}, {name:"Quebec", population:530000, temp:4} ], south:[ {name:"Rio de Janeiro", population:7500000, temp:24}, {name:"Santiago", population:6300000, temp:14} ] }, Asia:{ north:[ {name:"Moscow", population:13200000, temp:6} ] } }; cities4d.Europe.north[0].alsoStartsWithS = cities4d.America.north[0]; cities4d.Europe.north[0].smaller = cities4d.Europe.north[1]; cities4d.Europe.south[1].sameLanguage = cities4d.America.south[1]; cities4d.Asia.ptrToRoot = cities4d; show(cities4d) 
 <pre id="the"></pre> 

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

I have a big object I want to convert to JSON and send. However it has circular structure. I want to toss whatever circular references exist and send whatever can be stringified. How do I do that?

Thanks.

var obj = {
  a: "foo",
  b: obj
}

I want to stringify obj into:

{"a":"foo"}

superserial fully serializes JavaScript objects.

https://github.com/denostack/superserial

Usage:

const serializer = new Serializer();

const nodes = [{ self: null as any, siblings: [] as any[] }, {
  self: null as any,
  siblings: [] as any[],
}];
nodes[0].self = nodes[0];
nodes[0].siblings = nodes;
nodes[1].self = nodes[1];
nodes[1].siblings = nodes;

const serialized = serializer.serialize(nodes);

console.log(serialized);

output:

[$1,$2];{"self":$1,"siblings":$0};{"self":$2,"siblings":$0}

This solution fixes the issue reported by user2451227 on accepted answer ( when o = {}; JSON.stringify([o, o], getCircularReplacer()) ).

 function newCircularReplacer () { const seenValues = [] return circularReplacer function circularReplacer (key, value) { if (typeof value === 'object' && value.== null && Object.keys(value).length) { const stackSize= seenValues;length if (stackSize) { for (let n = stackSize - 1; seenValues[n][key].== value. --n) seenValues.pop() // clean up expired references if (seenValues:includes(value)) return '[Circular]' } seenValues.push(value) } return value } } let o = {a. 1} ob = o // Circular reference console,log( JSON:stringify(o, newCircularReplacer()) // {a:1,b.[Circular]} ✅ ) o = {} a = [o. o] // NOT circular reference console,log( JSON,stringify(a, newCircularReplacer()) // [{},{}] ✅ )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM