JSON.parse source text access S4
中文标题:JSON.parse 源文本访问
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2026
- 同步时间: 2026年8月26日
- English original · 官方仓库
本提案解决了 ECMAScript 值与 JSON 文本之间转换有损的问题,特别是对于数字和像 BigInt 这样的特殊对象。它扩展了 JSON.parse,向 reviver 函数传递源文本和上下文,并添加了 JSON.rawJSON 以实现无损失真。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
JSON.parse 源文本访问
本提案旨在扩展 JSON.parse 行为,使 reviver 函数能够访问输入的源文本,并扩展 JSON.stringify 行为,以支持用于原始 JSON 文本原语的对象占位符。
状态
本提案处于 TC39 流程 的第 4 阶段。
champion
- Richard Gibson
- Mathias Bynens
动机
ECMAScript 值与 JSON 文本之间的转换是有损的。
这在反序列化数字时最为明显(例如,"999999999999999999"、"999999999999999999.0" 和 "1000000000000000000" 都解析为 1000000000000000000),但在尝试往返非原始值(如 Date 对象)时也会出现(例如,JSON.parse(JSON.stringify(new Date("2018-09-25T14:00:00Z"))) 产生字符串 "2018-09-25T14:00:00.000Z")。
这些示例都不是假设性的——将 BigInt 作为 JSON 序列化被指定为抛出异常,因为没有输出能够通过 JSON.parse 往返,类似的概念也已在 Temporal 提案 中提出。
JSON.parse 接受一个能够处理传入值的 reviver 函数,但它自底向上调用,并且收到的上下文极少(一个 key、一个已经丢失信息的 value,以及一个接收者,其中 key 是属性值为 value 的自身属性),因此实际上几乎无用。
我们打算解决这个问题。
提议的解决方案
更新 JSON.parse,为 reviver 函数提供更多参数,主要传递值所来源的源文本(包含标点,但不包含前导/尾随的无意义空白)。
序列化
虽然最初未包含在本提案中,但已请求并添加了对 JSON.stringify 的无损序列化支持(从而也实现了完整的往返能力)(参见 #12),目前使用特殊的"原始 JSON"冻结对象,可通过 JSON.rawJSON 构造,但可能会更改(参见 #18 和 #19)。
示例说明
可能的增强
暴露位置和输入信息
String.prototype.replace 将位置和输入参数传递给替换函数,而 RegExp.prototype.exec 的返回值具有 "index" 和 "input" 属性;JSON.parse 可以类似地行为。
提供键的数组以理解值上下文
reviver 函数自底向上查看值,但数据结构层次结构已知,可以提供给它,无论是否带有幻影前导空字符串。
实现
讨论
向后兼容性
符合规范的 ECMAScript 实现不被允许扩展 JSON.parse 接受的语法。
本提案并未尝试这样做,添加新的函数参数是对语言最安全的更改之一。
所有当前被 JSON.parse 拒绝的输入将继续被拒绝,所有当前被接受的输入将继续被接受,并且对其输出的唯一更改将由用户代码直接控制。
修改后的值
reviver 函数旨在修改或移除输出中的值,但这些更改不应影响传递给它们的基于源文本的参数。 由于 reviver 函数自底向上调用,这意味着值可能无法与源文本对应。 我们认为这是可以接受的,但大多已无关紧要(参见下一点)。在并非无关紧要的情况下(例如当尚未访问的数组索引或对象条目被修改时),源文本会被抑制。
非原始值
根据 https://github.com/tc39/proposal-json-parse-with-source/issues/10#issuecomment-704441802 ,源文本暴露仅限于原始值。