This question has already got some reviews, so I could partially improve my code: please look at my self-answer below, which also contains comments about the review.
I'm frequently interested to answer SO questions regarding (JS) objects and/or arrays manipulation.
When providing a snippet, and if the actual result looks somewhat complex, it's not enough to merely console.log()
it, because it's rendered as a compacted (and often even reduced) single line where it's not easy to directly retrieve each piece of data.
Then I was tired to have to either spend time to arrange the output a bit (but generally not completely) or let the result appear unclear, so I decided to write a helper function for that:
/**
* @param src: any variable of any type
* @param html: output format (true|false); default = false
* @param level: (internal, don't use)
*
* @return string: formatted output
*/
function showObj(src, html, level) {
level |= 0;
const tabCount = 4,
edges = '{[}]';
var tab = (!!html ? ' ' : ' ').repeat(tabCount),
br = !!html ? '<br />' : '\n',
offset = tab.repeat(level);
switch (typeof src) {
case 'boolean':
case 'number': return src.valueOf();
case 'string': return '"' + src.toString() + '"';
case 'symbol': return src.toString();
case 'undefined': return 'undefined';
case 'function': return (src.name || 'function') + '()';
case 'object':
if (src === null) {return 'null';}
if (src === this) {return src.valueOf();}
if (!!src.jquery) {return 'jQuery ' + src.jquery + ' object';}
if (!Object.keys(src).length) {return src;}
var output = [],
isArr = Array.isArray(src);
for (let key in src) {
output.push(
br + offset + tab + (isArr ? '' : ('"' + key + '": ')) +
showObj(src[key], html, level + 1)
);
}
return edges[+isArr] + output.join(', ') + br + offset + edges[+isArr + 2];
default:
return '(unexpected!) ' + typeof src;
}
}
/**
* @param src: any variable of any type
* @param html: output format (true|false); default = false
* @param level: (internal, don't use)
*
* @return string: formatted output
*/
function showObj(src, html, level) {
level |= 0;
const tabCount = 4,
maxString = 40,
edges = '{[}]';
var tab = (!!html ? ' ' : ' ').repeat(tabCount),
br = !!html ? '<br />' : '\n',
offset = tab.repeat(level);
switch (typeof src) {
case 'boolean':
case 'number': return src.valueOf();
case 'string': return '"' + src.toString().substr(0, maxString) +
(src.length > maxString ? '...' : '') + '"';
case 'symbol': return src.toString();
case 'undefined': return 'undefined';
case 'function': return (src.name || 'function') + '()';
case 'object':
if (src === null) {return 'null';}
if (src === this) {return src.valueOf();}
if (!!src.jquery) {return 'jQuery ' + src.jquery + ' object';}
if (!Object.keys(src).length) {return src;}
var output = [],
isArr = Array.isArray(src);
for (let key in src) {
output.push(
br + offset + tab + (isArr ? '' : ('"' + key + '": ')) +
showObj(src[key], html, level + 1)
);
}
return edges[+isArr] + output.join(', ') + br + offset + edges[+isArr + 2];
default:
return '(unexpected!) ' + typeof src;
}
}
var src = {
'null': null,
'undefined': undefined,
'this': this,
'integer': 123,
'float': 12.3,
'Infinity': Infinity,
'NaN': NaN,
'Math.PI': Math.PI,
'string': 'Some short string',
'long-string': showObj.toSource(),
'bool-true': true,
'bool-false': false,
'date': new Date(),
'regexp': /.*/i,
'error': new Error('Error message'),
'symbol': Symbol('someSymbol'),
'function': function someFunc() {},
'anonymous-func': function() {},
'simple-array': [1, 2, 3],
'simple-object': {a: 'A', b: 'B', c: 'C'},
'compound-object': {
'compound-array': [
{'integer': 123, 'float': 12.3},
{'NaN': NaN, 'string': 'A string'},
{
'sub-array': [1, 2, 3],
'sub-object': {a: 'A', b: 'B', c: 'C'}
}
]
},
'jQuery': $('body'),
'map': new Map([['key1', 'value1'], ['key2', 'value2']]),
'set': new Set(['value1', 'value2', 'value3'])
};
console.log(showObj(src));
document.write(showObj(src, true));
* {
font-family: "Courier New";
font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I tried to make it together:
- Complete, i.e. distinguishing each kind of data structure I could think to (but maybe I forgotten some cases?).
- Clear but concise, e.g. cutting long strings, omitting to expand
this
or jQuery objects, and so on. - Also with a reduced code (I'm not re-writing a console :).
I'm expecting comments about especially the three aspects above, as well as about anything wrong I might have done.
level =( typeof level == 'undefined') ? 0 : level;
. Since it's expected that the most outer call toshowObj()
doesn't specify any 3rd argument, it works with 0 as value forlevel
. \$\endgroup\$level = level | 0
; not a logical OR. It works here because level is intended to be an integer, and bitwise OR zero is "safe". If level was 2 and you used 1 as the "default" instead of zero, you'd get2 | 1 => 3
\$\endgroup\$