Pretty-printing is implemented natively in JSON.stringify(). The third argument enables pretty printing and sets the spacing to use:
var str = JSON.stringify(obj, null, 2); // spacing level = 2
If you need syntax highlighting, you might use some regex magic like so:
function syntaxHighlight(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
See in action here: jsfiddle
Or a full snippet provided below:
function output(inp) {
document.body.appendChild(document.createElement('pre')).innerHTML = inp;
}
function syntaxHighlight(json) {
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
var obj = {a:1, 'b':'foo', c:[false,'false',null, 'null', {d:{e:1.3e5,f:'1.3e5'}}]};
var str = JSON.stringify(obj, undefined, 4);
output(str);
output(syntaxHighlight(str));
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
.null { color: magenta; }
.key { color: red; }
Answer from user123444555621 on Stack OverflowPretty-printing is implemented natively in JSON.stringify(). The third argument enables pretty printing and sets the spacing to use:
var str = JSON.stringify(obj, null, 2); // spacing level = 2
If you need syntax highlighting, you might use some regex magic like so:
function syntaxHighlight(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
See in action here: jsfiddle
Or a full snippet provided below:
function output(inp) {
document.body.appendChild(document.createElement('pre')).innerHTML = inp;
}
function syntaxHighlight(json) {
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
var obj = {a:1, 'b':'foo', c:[false,'false',null, 'null', {d:{e:1.3e5,f:'1.3e5'}}]};
var str = JSON.stringify(obj, undefined, 4);
output(str);
output(syntaxHighlight(str));
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
.null { color: magenta; }
.key { color: red; }
User Pumbaa80's answer is great if you have an object you want pretty printed. If you're starting from a valid JSON string that you want to pretty printed, you need to convert it to an object first:
var jsonString = '{"some":"json"}';
var jsonPretty = JSON.stringify(JSON.parse(jsonString),null,2);
This builds a JSON object from the string, and then converts it back to a string using JSON stringify's pretty print.
I would recommend using JSON.stringify, which converts the set of the variables in the object to a JSON string.
var obj = {
name: 'myObj'
};
JSON.stringify(obj);
Most modern browsers support this method natively, but for those that don't, you can include a JS version.
Use javascript String() function
String(yourobject); //returns [object Object]
or stringify()
JSON.stringify(yourobject)
I am prejudiced against variables named data.
You need to escape literal ", \, and \n characters in quoted strings. It's good form to do tabs too.
Using a dispatch table for types (instead of if/else) makes it easy to handle all the types.
Instead of passing tab up and down the call stack, wrap the calls in a function that indents a block of text. Nested traverse will be nested in indent too and get indented the right number of times.
Instead of checking whether you're at the end of a delimited list (to decide whether to add a delimiter), use arr.join(delimiter). It puts delimiters on inner boundaries only.
Array(n).fill(' ').join(''); is the same as ' '.repeat(n).
It would be nice to omit the quotes on property names that don't need them. Doing this perfectly happens to be really laborious—the regex is 11 kilobytes long!! It's manageable if we limit the exceptions to 7-bit ASCII, which is probably a good idea anyway.
function prettyPrint(obj) {
const stringify = {
"undefined": x => "undefined",
"boolean": x => x.toString(),
"number": x => x,
"string": x => enquote(x),
"object": x => traverse(x),
"function": x => x.toString(),
"symbol": x => x.toString()
},
indent = s => s.replace(/^/mg, " "),
keywords = `do if in for let new try var case else enum eval null this true
void with await break catch class const false super throw while
yield delete export import public return static switch typeof
default extends finally package private continue debugger
function arguments interface protected implements instanceof`
.split(/\s+/)
.reduce( (all, kw) => (all[kw]=true) && all, {} ),
keyify = s => ( !(s in keywords) && /^[$A-Z_a-z][$\w]*$/.test(s) ? s : enquote(s) ) + ": ",
enquote = s => s.replace(/([\\"])/g, '\\$1').replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/^|$/g,'"'),
traverse = obj => [
`{`,
indent( Object.keys(obj)
.map( k => indent( keyify(k) + stringify[ typeof obj[k] ](obj[k]) ) )
.join(",\n")
),
`}`
]
.filter( s => /\S/.test(s) )
.join("\n")
.replace(/^{\s*\}$/,"{}");
return traverse(obj);
}
console.log(prettyPrint(
{
"name":"Jon",
"facts":{
"car":"Ford",
"address":{
"city":"New York"
},
"watch":"Casio",
"other": {
"true":false,
blargh:undefined,
"111number":1e5,
method:function(x){x++}
}
}
}
));
A quick warning.
Javascript objects are referenced and that means objects can contain cyclic references. You function does not check for cyclic references. Cyclic references are very common in JavascripT so you should protect against the potential error.
Some solutions.
- You can use a
Setto track which objects have already been processed and step over repeats. - Add a depth argument that limits the recursion depth.
You can just let it throw a call stack overflow when the recursion gets too deep. However a warning, some browsers support tail call optimization and can recurse infinitely. Your function is not currently a tail call, but be aware as it could force the user to crash / close the page.
Example of cyclic object
const A = {A: "Prop B be will reference Self" };
A.B = A;