javascript 限制 JSON 字符串化深度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16466220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Limit JSON stringification depth
提问by Joachim Kurz
When stringifying an object using JSON.stringify
(or something similar) is there a way to limit the stringification depth, i.e. only go nlevels deep into the object tree and ignore everything that comes after that (or better: put placeholders in there, indicating something was left out)?
当使用JSON.stringify
(或类似的东西)对对象进行字符串化时,是否有一种方法可以限制字符串化深度,即只深入到对象树的n级并忽略之后的所有内容(或者更好:将占位符放在那里,表明有什么东西被留下了出去)?
I know that JSON.stringify
takes a replacer function of the form function (key, value)
but I didn't find a way to get the depth in the original object of the current key-value-pair handed to the replacer function.
我知道这JSON.stringify
需要表单的替换函数,function (key, value)
但我没有找到一种方法来获取传递给替换函数的当前键值对的原始对象的深度。
Is there a way to do this with the default JSON.stringify implementation? Or have I reached a point where I should just implement the stringification myself? Or is there another stringification library you can recommend that has this option?
有没有办法用默认的 JSON.stringify 实现来做到这一点?还是我已经到了应该自己实施字符串化的地步?或者您可以推荐另一个具有此选项的字符串化库吗?
回答by Martin Braun
I wanted to stringify an object on the first level without including a third-party library / too much code.
我想在不包含第三方库/太多代码的情况下在第一级对对象进行字符串化。
In case you look for the same, here is a quick one-liner to do so:
如果您寻找相同的内容,这里有一个快速的单行代码:
var json = JSON.stringify(obj, function (k, v) { return k && v && typeof v !== "number" ? (Array.isArray(v) ? "[object Array]" : "" + v) : v; });
The top level object will have no key, so it's always simply returned, however anything that is not a "number" on the next level will be casted to a string incl. a special case for arrays, otherwise those would be exposed further more.
顶级对象将没有键,所以它总是简单地返回,但是任何在下一级不是“数字”的东西都将被转换为字符串,包括。数组的特殊情况,否则这些数组会暴露得更多。
If you don't like this special array case, please use my old solution, that I improved, too:
如果你不喜欢这个特殊的数组情况,请使用我的旧解决方案,我也改进了:
var json = JSON.stringify(obj, function (k, v) { return k && v && typeof v !== "number" ? "" + v : v; }); // will expose arrays as strings.
Passing an array instead of an object in the top level will work nonetheless in both solutions.
尽管如此,在顶层传递数组而不是对象在这两种解决方案中都有效。
EXAMPLES:
例子:
var obj = {
keyA: "test",
keyB: undefined,
keyC: 42,
keyD: [12, "test123", undefined]
}
obj.keyD.push(obj);
obj.keyE = obj;
var arr = [12, "test123", undefined];
arr.push(arr);
var f = function (k, v) { return k && v && typeof v !== "number" ? (Array.isArray(v) ? "[object Array]" : "" + v) : v; };
var f2 = function (k, v) { return k && v && typeof v !== "number" ? "" + v : v; };
console.log("object:", JSON.stringify(obj, f));
console.log("array:", JSON.stringify(arr, f));
console.log("");
console.log("with array string cast, so the array gets exposed:");
console.log("object:", JSON.stringify(obj, f2));
console.log("array:", JSON.stringify(arr, f2));
回答by James Wilkins
Here is a function that respects the built-in JSON.stringify()
rules while also limiting depth:
这是一个尊重内置JSON.stringify()
规则同时也限制深度的函数:
function stringify(val, depth, replacer, space) {
depth = isNaN(+depth) ? 1 : depth;
function _build(key, val, depth, o, a) { // (JSON.stringify() has it's own rules, which we respect here by using it for property iteration)
return !val || typeof val != 'object' ? val : (a=Array.isArray(val), 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(k, v, a?depth:depth-1); } }), o||(a?[]:{}));
}
return JSON.stringify(_build('', val, depth), null, space);
}
How it works:
怎么运行的:
_build()
is called recursively to build the nested objects and arrays to the requested depth.JSON.stringify()
is used to iterate over each object's immediate properties to respect the built-in rules. 'undefined' is always returned from the internal replacer so no JSON is actually constructed yet. Keep in mind, the first time the internal replacer is called the key is empty (which is the item to be stringified).JSON.stringify()
is called on the final result to produce the actual JSON.
_build()
递归调用以将嵌套对象和数组构建到请求的深度。JSON.stringify()
用于迭代每个对象的直接属性以遵守内置规则。'undefined' 总是从内部替换器返回,所以实际上还没有构造 JSON。请记住,第一次调用内部替换器时,键为空(这是要字符串化的项目)。JSON.stringify()
调用最终结果以生成实际的 JSON。
Example:
例子:
var value={a:[12,2,{y:3,z:{q:1}}],s:'!',o:{x:1,o2:{y:1}}};
console.log(stringify(value, 0, null, 2));
console.log(stringify(value, 1, null, 2));
console.log(stringify(value, 2, null, 2));
{}
{
"a": [
12,
2,
{}
],
"s": "!",
"o": {}
}
{
"a": [
12,
2,
{
"y": 3,
"z": {}
}
],
"s": "!",
"o": {
"x": 1,
"o2": {}
}
}
(for a version that handles cyclical references, see here: https://stackoverflow.com/a/57193345/1236397- includes a TypeScript version)
(对于处理循环引用的版本,请参见此处:https: //stackoverflow.com/a/57193345/1236397- 包括 TypeScript 版本)
Update: Fixed a bug where empty arrays rendered as empty objects.
更新:修复了空数组呈现为空对象的错误。
回答by Hyman Allan
Make a deep clone of your object (with a library such as low-dash), do what ever pruning you want to do and then pass it to JSON.stringify. I would not try to re-invent JSON.stringify, that is effort in the wrong place.
对您的对象进行深度克隆(使用诸如low-dash 之类的库),进行任何您想做的修剪,然后将其传递给 JSON.stringify。我不会尝试重新发明 JSON.stringify,那是在错误的地方努力。
[EDIT]looks like someone already did what you were suggesting: JSON.stringify deep objects
[编辑]看起来有人已经按照你的建议做了: JSON.stringify deep objects
I wouldn't recommend this though because the native JSON.stringify is always going to be faster and more robust
我不会推荐这个,因为原生 JSON.stringify 总是会更快更健壮
[EDIT]here is a library that seems to do what you want: http://philogb.github.io/jit/static/v20/Docs/files/Core/Core-js.html#$jit.json.prune
[编辑]这里是一个库,似乎做你想做的事:http: //philogb.github.io/jit/static/v20/Docs/files/Core/Core-js.html# $jit.json.prune