你真的懂 JSON 吗?那些被忽略的底层边界与性能陷阱

一、 语法边界:JSON 并不是 JavaScript 的子集

这是一个常见的误区。虽然 JSON 源于 JS,但它的规范(RFC 8259)比 JS 严格且局限得多。

1. 那些被"吞掉"的类型

在执行 JSON.stringify(obj) 时,JS 引擎会进行一套复杂的类型转换,而这些转换往往是非对称的:

  • undefined、函数、Symbol

    • 作为对象属性时:会被直接忽略(Key 都会消失)。
    • 作为数组元素 时:会被转化为 null
    • 独立值 时:返回 undefined
  • 不可枚举属性:默认会被完全忽略。

  • BigInt :会直接抛出 TypeError,因为 JSON 规范中没有对应的大数表示协议。

2. 数值的精度丢失

JSON 的数值遵循 IEEE 754 双精度浮点数。如果你在处理前端监控中的高精纳秒级时间戳,直接序列化可能会导致精度被截断。


二、 序列化的高级操纵:Replacer 与 toJSON 的深度应用

当你需要处理复杂的业务对象(比如含有循环引用或敏感数据)时,基础的 JSON.stringify 就不够用了。

1. toJSON:对象的自白

如果一个对象拥有 toJSON 方法,序列化时会优先调用它。这在处理复杂类实例(Class)时非常有用:

JavaScript

kotlin 复制代码
class User {
  constructor(name, pwd) { this.name = name; this.pwd = pwd; }
  toJSON() { return { name: this.name }; } // 自动屏蔽敏感字段
}

2. Replacer 过滤器:解决循环引用

面对嵌套极深的监控数据,循环引用会导致进程崩溃。我们可以利用 Replacer 的第二个参数(函数或数组)来进行"外科手术":

JavaScript

javascript 复制代码
const seen = new WeakSet();
const safeJson = JSON.stringify(data, (key, value) => {
  if (typeof value === "object" && value !== null) {
    if (seen.has(value)) return "[Circular]"; // 标记循环引用而非报错
    seen.add(value);
  }
  return value;
});

三、 性能深水区:V8 引擎是如何"吃"掉 JSON 的?

在 Node.js 服务端,大规模的 JSON 处理往往是 CPU 的头号杀手。

1. 为什么 JSON.parse 比 JS 字面量快?

这是一个反直觉的结论:解析一段字符串 JSON.parse('{"a":1}') 通常比 JS 引擎解析代码 {a:1} 快。

  • 原因 :JS 解析器需要进行复杂的词法和语法分析(考虑到变量提升、作用域等),而 JSON 解析器是单向、无状态的。
  • 优化建议 :对于大型静态配置,直接以字符串形式存放并用 JSON.parse 载入,能有效缩短代码冷启动的解析时间(Parse Time)。

2. 阻塞与内存的"双重打击"

  • 同步阻塞JSON.stringify 在处理 10MB 以上的对象时,会阻塞 Event Loop 几十毫秒。在高并发环境下,这足以导致后续请求全部超时。
  • 内存膨胀 :序列化时,V8 会先生成一个完整的巨大字符串放入堆内存中。如果你的对象接近 1GB,序列化过程可能会瞬间触发 OOM (Out of Memory)

3. 安全陷阱:JSON 劫持与注入

  • __proto__ 注入 :不安全的 JSON.parse(特别是在某些旧库中)可能被恶意构造的字符串攻击,通过原型链污染篡改全局逻辑。
相关推荐
777VG6 小时前
PostgreSQL +martin将多张表输出成一个 MVT
前端·数据库·postgresql
mayaairi7 小时前
JS循环语句深度解析:嵌套for、while与do...while
开发语言·前端·javascript
To_OC7 小时前
啃完流式输出:从一个卡顿的 LLM 接口开始,我搞懂了数据流到底怎么 “流”
前端·javascript·llm
阳光是sunny7 小时前
LangGraph实战教程:defer延迟节点——让收尾工作自动排到最后
前端·人工智能·后端
kyriewen8 小时前
我用了三周Claude Code Skills——总结出5条铁律,第3条最反直觉
前端·ai编程·claude
阳光是sunny8 小时前
LangGraph实战教程:控制流详解
前端·人工智能·后端
格尔曼Noah9 小时前
Safari浏览器中如何只允许指定网站下载
前端·safari
用户059540174469 小时前
用了3年Redis,才发现我一直没搞懂缓存一致性测试
前端·css
swipe10 小时前
07|(前端转后全栈)为什么后端也要缓存?从前端缓存思维理解 Redis
前端·后端·全栈
IT小盘10 小时前
05-企业项目统一接入多个大模型-适配器模式实战
前端·人工智能·适配器模式