これは、組み込みの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);
}
注:配列は文字列のように扱われます-プリミティブ値の配列。したがって、ネストされたオブジェクトアイテムは、配列オブジェクト自体ではなく、次のレベルとして扱われます(文字列を文字の配列にする方法とよく似ていますが、1つのエンティティです)。
更新:空の配列が空のオブジェクトとしてレンダリングされるバグを修正しました。