JSON.stringify 深层对象

2023-11-26

我需要一个函数从任何参数构建 JSON 有效字符串,但是:

  • 通过不两次添加对象来避免递归问题
  • 通过截断超过给定深度来避免调用堆栈大小问题

一般来说,它应该能够处理大对象,但代价是截断它们。

作为参考,此代码失败:

var json = JSON.stringify(window);

避免递归问题很简单:

var seen = [];
return JSON.stringify(o, function(_, value) {
    if (typeof value === 'object' && value !== null) {
        if (seen.indexOf(value) !== -1) return;
        else seen.push(value);
    }
    return value;
});

但目前,除了复制和更改道格拉斯·克罗克福德的代码为了跟踪深度,我没有找到任何方法来避免非常深的对象上的堆栈溢出,例如window or any event。有简单的解决办法吗?


我做了我最初担心我必须做的事情:我采用了 Crockford 的代码并根据我的需要对其进行了修改。现在它构建 JSON 但处理

  • cycles
  • 物体太深
  • 数组太长
  • 异常(无法合法访问的访问器)

为了以防万一有人需要它,我创建了一个 GitHub 存储库:GitHub 上的 JSON.prune

这是代码:

// JSON.pruned : a function to stringify any object without overflow
// example : var json = JSON.pruned({a:'e', c:[1,2,{d:{e:42, f:'deep'}}]})
// two additional optional parameters :
//   - the maximal depth (default : 6)
//   - the maximal length of arrays (default : 50)
// GitHub : https://github.com/Canop/JSON.prune
// This is based on Douglas Crockford's code ( https://github.com/douglascrockford/JSON-js/blob/master/json2.js )
(function () {
    'use strict';

    var DEFAULT_MAX_DEPTH = 6;
    var DEFAULT_ARRAY_MAX_LENGTH = 50;
    var seen; // Same variable used for all stringifications

    Date.prototype.toPrunedJSON = Date.prototype.toJSON;
    String.prototype.toPrunedJSON = String.prototype.toJSON;

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };

    function quote(string) {
        escapable.lastIndex = 0;
        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string'
                ? c
                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }

    function str(key, holder, depthDecr, arrayMaxLength) {
        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            partial,
            value = holder[key];
        if (value && typeof value === 'object' && typeof value.toPrunedJSON === 'function') {
            value = value.toPrunedJSON(key);
        }

        switch (typeof value) {
        case 'string':
            return quote(value);
        case 'number':
            return isFinite(value) ? String(value) : 'null';
        case 'boolean':
        case 'null':
            return String(value);
        case 'object':
            if (!value) {
                return 'null';
            }
            if (depthDecr<=0 || seen.indexOf(value)!==-1) {
                return '"-pruned-"';
            }
            seen.push(value);
            partial = [];
            if (Object.prototype.toString.apply(value) === '[object Array]') {
                length = Math.min(value.length, arrayMaxLength);
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value, depthDecr-1, arrayMaxLength) || 'null';
                }
                v = partial.length === 0
                    ? '[]'
                    : '[' + partial.join(',') + ']';
                return v;
            }
            for (k in value) {
                if (Object.prototype.hasOwnProperty.call(value, k)) {
                    try {
                        v = str(k, value, depthDecr-1, arrayMaxLength);
                        if (v) partial.push(quote(k) + ':' + v);
                    } catch (e) { 
                        // this try/catch due to some "Accessing selectionEnd on an input element that cannot have a selection." on Chrome
                    }
                }
            }
            v = partial.length === 0
                ? '{}'
                : '{' + partial.join(',') + '}';
            return v;
        }
    }

    JSON.pruned = function (value, depthDecr, arrayMaxLength) {
        seen = [];
        depthDecr = depthDecr || DEFAULT_MAX_DEPTH;
        arrayMaxLength = arrayMaxLength || DEFAULT_ARRAY_MAX_LENGTH;
        return str('', {'': value}, depthDecr, arrayMaxLength);
    };

}());

可以做什么的示例:

var json = JSON.pruned(window);

Note:与此答案中的代码相反,GitHub 存储库在需要时更新(文档、兼容性、在 commonjs 或 Node 中用作模块、特定序列化等)。如果您需要此修剪功能,最好从存储库开始。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JSON.stringify 深层对象 的相关文章

随机推荐

  • 为什么Angular的DI内联注释中的函数是数组元素?

    我有一个问题想问 AngularJS 的人 所以 我现在使用 Angular 已经有一段时间了 然而 每次当我编写新的控制器或使用依赖注入的东西时 我发现自己写错了内联定义 someModule controller MyControlle
  • 无法在 POSTMan 上获取 Google oAuth 2 令牌

    嗯 自从其他问题 已解决 仍未解决 我正在考虑使用 POSTMan 对客户端库将执行的每个步骤进行试验和错误 所以我读了基本步骤再次使用 Google OAuth2 创建了另一个 OAuth 2 IDApi 管理器 gt 凭证在Dev Co
  • 您会推荐哪些 WPF 书籍? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心以获得指导 Locked 这个问题及其
  • Django MultiWidget 电话号码字段

    我想创建一个电话号码输入字段 其中有 2 个文本字段 大小分别为 3 3 和 4 并带有常见的 分隔符 下面是我的字段和小部件的代码 在初始渲染期间尝试迭代表单中的字段时出现以下错误 当 for 循环到达我的电话号码字段时会发生这种情况 渲
  • 如何在不使用谷歌地图方向 API 的情况下查找 Android 应用程序中 2 个地理点之间的距离(通过道路)?

    我正在开发一个 Android 应用程序 我需要找到两个地理坐标之间的距离 I used Location distanceBetween and Location distanceTo 功能 这些函数给出的是直线距离 但当我们通过公路旅行
  • 如果db文件不存在,如何使sqlite3.connect()失败?

    sqlite3 connect 如果 db 文件不存在 将创建它 我希望它失败 有办法这样做吗 第一种方法是检查文件路径os path isfile import sqlite3 import os my path database db
  • 使用 ODR 拟合数据中的上限和不对称误差的 Python 幂律

    我正在尝试使用 python 将一些数据拟合到幂律中 问题是我的一些点是上限 我不知道如何将其包含在拟合程序中 在数据中 我将上限设置为 y 的误差等于 1 而其余的要小得多 您可以将此错误设置为 0 并更改 uplims 列表生成器 但拟
  • 强制 MapKit 仅使用缓存的地图图块/以编程方式禁用网络

    我们偶然发现了这样一个问题 我们正在开发一款旅行应用程序 为了确保用户不会在我们的应用程序中花费太多漫游费 我们决定实现一个设置选项 供用户仅查看缓存的地图 因此 我们让用户决定是否要从互联网加载地图 或者想要省钱并查看缓存的地图 存储在
  • InternetExplorer.Application 对象和 cookie 容器

    我有以下用 VB NET 编写的控制台应用程序 Sub Main Dim ie As Object CreateObject InternetExplorer Application ie Visible True ie Navigate2
  • Webform 中的 HTML 助手?

    我有一个旧网站 我想使用 HTML 助手之类的东西来生成特殊的 HTML 在本例中为复杂的按钮 我知道这在 ASP NET MVC 中是如何工作的 但我如何在 Webform 而不是 Razor 中做到这一点 我读过有关静态方法的建议 如下
  • 表单提交失败后显示服务器端验证错误

    表单提交失败后如何显示验证消息 API 请求返回 HTTP 400 application problem json 响应 并包含违规行为作为带有字段路径的列表 https www rfc editor org rfc rfc7807 se
  • 在Java中处理文件指针的有效方法? (使用 BufferedReader 和文件指针)

    我有一个每秒更新的日志文件 我需要定期读取日志文件 一旦执行读取 我需要将文件指针位置存储在我读取的最后一行的末尾 并且在下一个定期读取中我应该从该点开始 目前 我正在 Java 中使用随机访问文件并使用getFilePointer 方法来
  • JAR 文件的正确内部结构是什么

    这是一个非常愚蠢的问题 我找不到明确的答案 背景 我正在使用 Eclipse 在 XP 终端上使用 ANT 插件之一 我刚刚开始使用 ANT 在 jar 指令中 我正在设置已完成的 JAR 文件的位置 当我 解压缩 该文件时 我得到以下内容
  • 为什么使用 Instant 将 1582 年之前的 Java 日期转换为 LocalDate 会给出不同的日期?

    考虑这段代码 Date date new SimpleDateFormat MMddyyyy parse 01011500 LocalDate localDateRight LocalDate parse formatter format
  • 插入金钱时使用的 SQL 数据类型

    我正在使用 Oracle SQL 数据库 我必须插入货币值 工资 作为行的一部分 由于某种奇怪的原因 金钱命令不起作用 是否有任何替代方法可以解决这个问题 数据输入格式 00 000 000 CREATE TABLE staff staff
  • 使用 Compact Framework 设置数据网格中的列宽

    我正在尝试设置数据网格中列的宽度 我使用 Compact Framework 2 0 和 C 我尝试了这个 但它给了我一个 超出债券 的错误消息 foreach DataGridColumnStyle vColumnStyle in dat
  • 如何与子进程共享父进程的 numpy 随机状态?

    我在程序开始时设置了 numpy 随机种子 在程序执行期间 我使用多次运行一个函数multiprocessing Process 该函数使用 numpy random 函数来绘制随机数 问题是Process获取当前环境的副本 因此 每个进程
  • 我们如何在React js中使用axios发送OAuth2.0

    我正在解决一个身份验证问题 我必须为我的 React 应用程序实现 OAuth2 0 身份验证 有什么方法可以使用基于 Axios Promise 的库进行身份验证吗 您必须在标头中传递您的令牌 见下文 const instance axi
  • 在 Perl 中比较多个字符串

    我的代码是这样的 if var eq str1 var eq str2 var eq str3 有没有办法优化这个 我想要类似的东西 if var eq str1 str2 str3 根据字符串的内容 正则表达式非常方便 if var st
  • JSON.stringify 深层对象

    我需要一个函数从任何参数构建 JSON 有效字符串 但是 通过不两次添加对象来避免递归问题 通过截断超过给定深度来避免调用堆栈大小问题 一般来说 它应该能够处理大对象 但代价是截断它们 作为参考 此代码失败 var json JSON st