ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

jstips 系列第 40 期:用 JSON.stringify 选择性序列化与美化输出对象

jstips 系列第 40 期:用 JSON.stringify 选择性序列化与美化输出对象 教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载本篇技术指南围绕 jstips 仓库 第 40 期技巧《Usando JSON.Stringify》英文版见 _posts/en/javascript/2016-02-09-using-json-stringify.md展开核心讲解JSON.stringify的第二个参数replacer数组或函数如何实现“只挑选指定属性序列化”以及第三个参数space如何控制缩进格式。读完你将掌握用数组白名单过滤对象字段、用函数做键级精细裁剪甚至替换值、以及按需生成带缩进的可读 JSON 文本从而在日志输出、接口返回裁剪、调试打印等场景中写出更简洁、更可控的序列化代码。一、JSON.stringify的三个参数与“附加参数”的来历在日常开发中JSON.stringify(obj)是最常见的用法把一个 JavaScript 对象转成 JSON 字符串。但正如本 tip 开头所说——当对象上带有prop1、prop2、prop3等多个属性时我们“可以通过传递附加参数给JSON.stringify来选择性地将属性生成字符串”。JSON.stringify的完整签名是JSON.stringify(value[, replacer[, space]])value要序列化的对象或值replacer附加参数之一可以是属性名数组也可以是函数用于控制序列化过程中包含哪些属性、以及属性值如何被改写space附加参数之二可以是数字或字符串用于控制输出字符串的缩进与美化格式。本 tip 的全部内容正是围绕这两个“附加参数”展开的先演示数组形式的属性选择再升级为函数形式的键级过滤最后展示第三个参数对输出格式的修饰。二、用数组作为replacer按白名单选择性序列化假设有一个对象包含prop1、prop2、prop3三个属性。如果我们只想把其中两个属性写入 JSON 字符串可以像下面这样传入一个属性名数组var obj { prop1: value1, prop2: value2, prop3: value3 }; var selectedProperties [prop1, prop2]; var str JSON.stringify(obj, selectedProperties); // str // {prop1:value1,prop2:value2}运行后得到的str将只包含被选中属性的信息{prop1:value1,prop2:value2}这里selectedProperties数组相当于一张白名单只有数组中列出的属性名才会被序列化其余属性如prop3会被直接忽略。几个值得注意的细节数组中元素的顺序会影响输出 JSON 中键的顺序数组只接受字符串或数字类型的属性名其他类型会被忽略如果数组中出现对象上不存在的属性名该名称会被直接跳过不会报错数组方式对嵌套对象同样生效吗不完全生效——数组只会作用于顶层对象replacer数组中的名称会按“从根到叶的每一层”匹配但要精确裁剪嵌套结构更可靠的方式是使用函数形式的replacer见下一节。这种“白名单”思想在仓库中并非孤例第 70 期技巧《Picking and rejecting object properties》 用pick/reject两个函数实现了对对象属性的选择与剔除其中pick(row, [client.name])的用法与本 tip 的数组白名单如出一辙可以对照阅读理解“按需取字段”这一模式在序列化与普通对象操作中的两种落地形态。三、用函数作为replacer键级过滤与值改写数组只能做“属性名集合”级别的过滤无法表达更复杂的逻辑例如按属性值的类型、按键名模式、或对某个值做特殊改写。本 tip 随即给出第二种用法把函数作为第二个参数。function selectedProperties(key, val) { // 第一次调用时val 是整个对象key 是空字符串 if (!key) { return val; } if (key prop1 || key prop2) { return val; } return; }使用时var str JSON.stringify(obj, selectedProperties); // {prop1:value1,prop2:value2}3.1 函数形式的调用机制当replacer是函数时序列化过程中每个键值对都会被调用一次函数接收两个参数参数含义第一次调用的特殊值key当前属性的键名空字符串val当前属性的值整个根对象所以上面的函数第一行if (!key) { return val; }是必不可少的“保险丝”在第一次调用key 为空字符串时把整个对象原样返回否则对象会被整个丢弃。之后的每次调用中返回val表示保留该属性返回undefined代码中直接return;表示删除该属性返回其他任意值则表示用该值替换当前属性值这正是函数形式比数组更强大的地方——你可以在序列化过程中对值做加工例如脱敏、类型转换、格式化日期等。3.2 从源码/规范层面的行为细节结合 ECMAScript 规范与 Node.js 的实际实现本仓库为纯文档型 jstips 集合无运行时代码但该行为在各大 JS 引擎中一致返回值处理规则若返回undefined或返回一个函数则该属性被跳过对Number值若返回的数值本身也是NaN、Infinity会被序列化为null对嵌套对象replacer函数会递归地作用到每一层属性上而数组形式在嵌套上的控制力较弱因此函数形式是处理深层对象裁剪的首选注意this上下文调用replacer时this指向当前正在序列化的对象即该属性所在的对象可以利用这一点实现按所在层级做不同处理。把上面的过滤函数稍作扩展即可实现“剔除值为函数或undefined的字段”等常见诉求function sanitize(key, val) { if (!key) return val; // 保留根对象 if (typeof val function) return undefined; // 函数值跳过 if (val undefined) return undefined; // undefined 跳过 return val; }四、第三个参数space控制输出的缩进与可读性本 tip 指出“最后一个可选参数可以修改生成字符串的方式。”也就是第三个参数space。它接受两类值数字代表每层缩进的空格数上限 10超过按 10 处理最小为 0 表示不缩进字符串直接作为每一层的缩进前缀长度最多取前 10 个字符。4.1 传入制表符字符串本 tip 的示例传入的是双制表符字符串var str JSON.stringify(obj, selectedProperties, \t\t); /* str 每行都以双制表符缩进输出如下 { prop1: value1, prop2: value2 } */注意输出注释中呈现的每行缩进正是\t\t两个制表符的效果从仓库原文的注释可以看到每个键值对独占一行且外层大括号与内层属性之间有统一的双制表符缩进。4.2 传入数字var str JSON.stringify(obj, selectedProperties, 2); /* 输出 { prop1: value1, prop2: value2 } */传入2时每层缩进两个空格这是最常用的美化格式。4.3 不传或传null的行为省略第三个参数或传入null、undefined输出为紧凑单行格式即最开始的{prop1:value1,prop2:value2}传入0或负数同样不产生缩进。space参数最大的价值在于可读性调试打印、日志输出、测试断言、以及把 JSON 展示给用户/写入配置文件时带缩进的格式化输出能显著降低阅读成本。本仓库 POST_TEMPLATE.md 中layout: post等元信息即采用 YAML 风格呈现读者可体会结构化、可读格式在内容组织中的价值。五、完整组合三个参数协同工作把本 tip 的三个示例串起来一个完整的“选择性序列化 美化输出”示例就是var obj { prop1: value1, prop2: value2, prop3: value3 }; // 方式一数组白名单 数字缩进 var str1 JSON.stringify(obj, [prop1, prop2], 2); // 方式二函数过滤 双制表符缩进 function selectedProperties(key, val) { if (!key) return val; // 保留根对象 if (key prop1 || key prop2) return val; return; // 其余属性一律跳过 } var str2 JSON.stringify(obj, selectedProperties, \t\t); console.log(str1); console.log(str2);两种方式输出语义相同区别在于数组方式代码更简洁、适合“固定白名单”函数方式更灵活、可处理嵌套与值改写。实践中可按需选择。六、应用场景与相关技巧对照6.1 日志与调试在日志里打印大型对象时先用白名单挑出关键字段再用space: 2美化既避免刷屏又保证可读console.log(JSON.stringify(user, [id, name, email], 2));6.2 接口返回裁剪与敏感字段剔除向客户端返回数据前用函数形式的replacer剔除password、token等敏感字段function safeReplacer(key, val) { if (!key) return val; if (key password || key token) return undefined; return val; }这一思路与仓库 第 39 期技巧《Advanced Properties》 中提到的“enumerable为 false 的属性不会出现在JSON.stringify结果中”互为补充一个是在序列化阶段主动过滤一个是在属性定义阶段控制可枚举性两者结合可构建更完善的字段可见性控制方案。6.3 与toJSON的配合进阶若对象本身定义了toJSON()方法JSON.stringify会优先调用它并用其返回值作为序列化对象此时replacer数组/函数仍可叠加生效。这是官方规范行为可用于自定义对象的序列化视图——但需注意toJSON必须返回可序列化类型的值。七、小结本 tip 用三个代码示例完整展示了JSON.stringify附加参数的三种能力数组形式的replacer按白名单挑出顶层属性代码最简洁函数形式的replacer以(key, val)形式逐键过滤支持嵌套对象、支持值改写、支持以return undefined剔除字段space参数用数字空格数或字符串如\t\t控制缩进生成可读的美化 JSON。这三个参数是JSON.stringify最容易被忽略、却最具实战价值的部分。掌握它们之后无论是日志调试、接口裁剪、还是敏感字段过滤都可以少写很多手写遍历代码让序列化这件事变得既精确又优雅。本文对应的原始技巧文档位于仓库 西语版 与 英文版并可结合 仓库 README 的 Tips 列表 中的第 40 期索引进一步了解整个 jstips 系列。赞分享教程【免费下载链接】jstipsThis is about useful JS tips!项目地址https://gitcode.com/gh_mirrors/js/jstips点击查看免费下载相关推荐DiceDB HEXISTS 命令详解校验 Hash 字段存在性与条件逻辑实战DiceDB HEXISTS 命令详解校验 Hash 字段存在性与条件逻辑实战 HEXISTS 是 DiceDB 中用于校验指定 key 所存储的 Hash教程jstips 第 40 期解读掌握 JSON.stringify 的附加参数按需序列化对象属性jstips 第 40 期解读掌握 JSON.stringify 的附加参数按需序列化对象属性 JSON.stringify 是 JavaScript 中最教程30-seconds-of-code使用 JSON.stringify 的第二参数实现对象键的选择性序列化30 seconds of code使用 JSON.stringify 的第二参数实现对象键的选择性序列化 JSON.stringify 是 JavaScri教程文档上一篇Telepresence 环境变量导入指南将集群容器环境变量带入本地开发下一篇node-emoji完全指南让Node.js项目轻松集成表情符号支持创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表