Pretty printing Javascript objects as JSON

Sometimes when working with Javascript objects, it is useful to print the objects out as JSON strings and take a look at their values. Take the following simple Javascript object:

// simple Javascript object
var obj = {
    a: { 
        b: "foo",
        c: "bar" },
    c: "baz",
    d: "qux"
};

If you print it out via console.log, it looks like this:

console.log(obj);
{ a: { b: 'foo', c: 'bar' }, c: 'baz', d: 'qux' }

This is okay for simple objects, but as you can see, without line breaks and indenting, it gets hard to read the values of the object when it starts to get complex. It would be nice to have the object “pretty” printed in Javascript Object Notation (JSON) with proper indenting and line feeds.

Enter the JSON.stringify function:

JSON.stringify(value[, replacer[, space]]);

As it says in it's description, JSON.stringify() converts a value to JSON notation representing it.

So, now calling console.log on a simple JSON.stringified value, the result looks like this:

console.log(JSON.stringify(obj, null, 4));
{
    "a": {
        "b": "foo",
        "c": "bar"
    },
    "c": "baz",
    "d": "qux"
}

This is great and it’s just the kind of output we want! But there’s one gotcha: sometimes Javascript objects contain circular references back to themselves. Take this object:

// simple obj with a circular reference
var obj = {
    a: { 
        b: "foo",
        c: "bar" },
    c: "baz",
    d: "qux"
};
obj.z = obj; // <-- circular reference back to itself!

Now, if you try to call the JSON.stringify function with the same variables as above, you will get a “circular structure” TypeError:

console.log(JSON.stringify(obj, null, 4));
TypeError: Converting circular structure to JSON
    at Object.stringify (native)
    at Object.<anonymous> (C:\workspace\example\example.js:50:22)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.runMain (module.js:575:10)
    at run (node.js:348:7)
    at startup (node.js:140:9)

This is no good – we don’t get any information about the object; only an error message. Often, it would still be nice to see the object’s non-circular data and ignore any circular reference data.

Rob W on StackOverflow addressed this issue by calling JSON.stringify with a custom replacer function. So by tweaking his example slightly, you can create a function that ignores the circular reference data, like this:

/**
 * Fxn that returns a JSON stringified version of an object.
 * This fxn uses a custom replacer function to handle circular references
 * see http://stackoverflow.com/a/11616993/3043369
 * param {object} object - object to stringify
 * returns {string} JSON stringified version of object
 */
function JSONStringify(object) {
    var cache = [];        
    var str = JSON.stringify(object,
        // custom replacer fxn - gets around "TypeError: Converting circular structure to JSON" 
        function(key, value) {
            if (typeof value === 'object' && value !== null) {
                if (cache.indexOf(value) !== -1) {
                    // Circular reference found, discard key
                    return;
                }
                // Store value in our collection
                cache.push(value);
            }
            return value;
        }, 4);
    cache = null; // enable garbage collection
    return str;
};

Then if you print out this function’s return value, you’ll see this:

console.log(JSONStringify(obj));
{
    "a": {
        "b": "foo",
        "c": "bar"
    },
    "c": "baz",
    "d": "qux"
}

Note that the obj.z value is not displayed in the output, but that’s the value with the circular reference. So we get exactly what we want – the object’s non-circular data and all circular references are ignored.

Here is a full example script and output:

// example.js - pretty print javascript objects as JSON

/**
 * Fxn that returns a JSON stringified version of an object.
 * This fxn uses a custom replacer function to handle circular references
 * see http://stackoverflow.com/a/11616993/3043369
 * param {object} object - object to stringify
 * returns {string} JSON stringified version of object
 */
function JSONStringify(object) {
    var cache = [];        
    var str = JSON.stringify(object,
        // custom replacer fxn - gets around "TypeError: Converting circular structure to JSON" 
        function(key, value) {
            if (typeof value === 'object' && value !== null) {
                if (cache.indexOf(value) !== -1) {
                    // Circular reference found, discard key
                    return;
                }
                // Store value in our collection
                cache.push(value);
            }
            return value;
        }, 4);
    cache = null; // enable garbage collection
    return str;
};

// simple obj with a circular reference
var obj = {
    a: { 
        b: "foo",
        c: "bar" },
    c: "baz",
    d: "qux"
};
obj.z = obj;

try {
    // print unformatted JSON object
    console.log('Test 1:');
    console.log(obj);
    console.log();
} catch (e) {
    console.error(e.stack + '\n');
}


try {
    // regular print your JSON object
    console.log('Test 2:');
    console.log(JSON.stringify(obj, null, 4));
} catch (e) {
    console.error(e.stack + '\n');
}


try {
    // print your JSON object & ignore circular references
    console.log('Test 3:');
    console.log(JSONStringify(obj));
} catch (e) {
    console.error(e.stack + '\n');
}

Output:

C:\workspace\example>node example.js
Test 1:
{ a: { b: 'foo', c: 'bar' }, c: 'baz', d: 'qux', z: [Circular] }

Test 2:
TypeError: Converting circular structure to JSON
    at Object.stringify (native)
    at Object.&lt;anonymous&gt; (C:\workspace\example\example.js:52:22)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:458:32)
    at tryModuleLoad (module.js:417:12)
    at Function.Module._load (module.js:409:3)
    at Module.runMain (module.js:575:10)
    at run (node.js:348:7)
    at startup (node.js:140:9)

Test 3:
{
    "a": {
        "b": "foo",
        "c": "bar"
    },
    "c": "baz",
    "d": "qux"
}
Software automation engineer in Portland, OR. LinkedIn: jantonypdx, Twitter: jantony_pdx
Posts created 10

3
Leave a Reply

avatar
2 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
NisarJohn AntonyAlexander Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
Alexander
Guest

Why aren’t there any comments? It is pretty cool. Thank you for your JSONStringify(object) function. Pretty useful at debugging. *thumbsup*

Nisar
Guest
Nisar

John – This is awesome, I’m a newbie who doesn’t understand JS well. The solution for “circular structure” TypeError is what I needed exactly.
Thank you so much, much appreciated!

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top