40

当使用JSON.stringify(或类似的东西)对对象进行字符串化时,有一种方法可以限制字符串化深度,即只深入对象树的n级并忽略之后出现的所有内容(或者更好:在其中放置占位符,表示留下了一些东西出去)?

我知道这JSON.stringify需要表单的替换函数,function (key, value)但我没有找到一种方法来获取传递给替换函数的当前键值对的原始对象的深度。

有没有办法使用默认的 JSON.stringify 实现来做到这一点?还是我已经到了应该自己实现字符串化的地步?或者您是否可以推荐另一个具有此选项的字符串化库?

4

3 回答 3

12

我想在不包含第三方库/太多代码的情况下在第一级对对象进行字符串化。

如果您寻找相同的东西,这里有一个快速的单行代码:

var json = JSON.stringify(obj, function (k, v) { return k && v && typeof v !== "number" ? (Array.isArray(v) ? "[object Array]" : "" + v) : v; });

顶级对象没有键,所以它总是简单地返回,但是下一层不是“数字”的任何东西都将被转换为字符串,包括。数组的特殊情况,否则它们会暴露得更多。

如果您不喜欢这种特殊的数组情况,请使用我改进的旧解决方案:

var json = JSON.stringify(obj, function (k, v) { return k && v && typeof v !== "number" ? "" + v : v; }); // will expose arrays as strings.

尽管如此,在顶层传递一个数组而不是一个对象在这两种解决方案中都可以工作。

例子:

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));

于 2017-10-24T10:39:27.617 回答
6

这是一个尊重内置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);
}

这个怎么运作:

  1. _build()递归调用以将嵌套对象和数组构建到请求的深度。JSON.stringify()用于迭代每个对象的直接属性以遵守内置规则。'undefined' 总是从内部替换器返回,因此实际上还没有构造任何 JSON。请记住,第一次调用内部替换器时,键是空的(这是要字符串化的项目)。
  2. JSON.stringify()在最终结果上调用以生成实际的 JSON。

例子:

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": {}
  }
}

(有关处理循环引用的版本,请参见此处:https : //stackoverflow.com/a/57193345/1236397 - 包括 TypeScript 版本)

更新:修复了空数组呈现为空对象的错误。

于 2019-07-25T01:22:44.493 回答
1

对您的对象进行深度克隆(使用诸如low-dash之类的库),执行您想做的任何修剪,然后将其传递给 JSON.stringify。我不会尝试重新发明 JSON.stringify,那是在错误的地方努力。

[编辑]看起来有人已经按照你的建议做了: JSON.stringify deep objects

不过我不推荐这样做,因为原生 JSON.stringify 总是会更快、更健壮

[编辑]这里是一个似乎做你想做的库:http: //philogb.github.io/jit/static/v20/Docs/files/Core/Core-js.html# $jit.json.prune

于 2014-04-04T11:22:36.423 回答