这是一个尊重内置 JSON.stringify() 规则同时限制深度的函数。此版本通过将循环引用设为 null 或使用可选回调来获取对象 ID(例如 GUID)来处理循环引用。
function stringify(val, depth, replacer, space, onGetObjID) {
depth = isNaN(+depth) ? 1 : depth;
var recursMap = new WeakMap();
function _build(val, depth, o, a, r) { // (JSON.stringify() has it's own rules, which we respect here by using it for property iteration)
return !val || typeof val != 'object' ? val
: (r = recursMap.has(val), recursMap.set(val,true), a = Array.isArray(val),
r ? (o=onGetObjID&&onGetObjID(val)||null) : JSON.stringify(val, function(k,v){ if (a || depth > 0) { if (replacer) v=replacer(k,v); if (!k) return (a=Array.isArray(v),val=v); !o && (o=a?[]:{}); o[k] = _build(v, a?depth:depth-1); } }),
o===void 0 ? (a?[]:{}) : o);
}
return JSON.stringify(_build(val, depth), null, space);
}
var o = {id:'SOMEGUID',t:true};
var value={a:[12,2,{y:3,z:{o1:o}}],s:'!',b:{x:1,o2:o,o3:o}};
console.log(stringify(value, 0, (k,v)=>{console.log('key:'+k+';val:',v); return v}, 2));
console.log(stringify(value, 1, (k,v)=>{console.log('key:'+k+';val:',v); return v}, 2));
console.log(stringify(value, 2, (k,v)=>{console.log('key:'+k+';val:',v); return v}, 2));
console.log(stringify(value, 3, (k,v)=>{console.log('key:'+k+';val:',v); return v}, 2));
console.log(stringify(value, 4, (k,v)=>{console.log('key:'+k+';val:',v); return v}, 2, (v)=>{return v.id}));
{}
{
"a": [
12,
2,
{}
],
"s": "!",
"b": {}
}
{
"a": [
12,
2,
{
"y": 3,
"z": {}
}
],
"s": "!",
"b": {
"x": 1,
"o2": {},
"o3": null
}
}
{
"a": [
12,
2,
{
"y": 3,
"z": {
"o1": {}
}
}
],
"s": "!",
"b": {
"x": 1,
"o2": null,
"o3": null
}
}
{
"a": [
12,
2,
{
"y": 3,
"z": {
"o1": {
"id": "SOMEGUID",
"t": true
}
}
}
],
"s": "!",
"b": {
"x": 1,
"o2": "SOMEGUID",
"o3": "SOMEGUID"
}
(取自我在这里的帖子https://stackoverflow.com/a/57193068/1236397)
这是一个typescript版本:
/** A more powerful version of the built-in JSON.stringify() function that uses the same function to respect the
* built-in rules while also limiting depth and supporting cyclical references.
*/
export function stringify(val: any, depth: number, replacer: (this: any, key: string, value: any) => any, space?: string | number, onGetObjID?: (val: object) => string): string {
depth = isNaN(+depth) ? 1 : depth;
var recursMap = new WeakMap();
function _build(val: any, depth: number, o?: any, a?: boolean, r?: boolean) {
return !val || typeof val != 'object' ? val
: (r = recursMap.has(val),
recursMap.set(val, true),
a = Array.isArray(val),
r ? (o = onGetObjID && onGetObjID(val) || null) : JSON.stringify(val, function (k, v) { if (a || depth > 0) { if (replacer) v = replacer(k, v); if (!k) return (a = Array.isArray(v), val = v); !o && (o = a ? [] : {}); o[k] = _build(v, a ? depth : depth - 1); } }),
o === void 0 ? (a?[]:{}) : o);
}
return JSON.stringify(_build(val, depth), null, space);
}
注意:数组被视为字符串 - 原始值数组;因此,任何嵌套的对象项都被视为下一级,而不是数组对象本身(很像字符串可以是字符数组,但它是一个实体)。
更新:修复了空数组呈现为空对象的错误。