JavaScript (Node.js) 中的对象序列化:从 JSON 到二进制格式
序列化是将复杂的数据结构(对象、数组、Map、Set)转换为可以保存到文件、通过网络传输或发送到其他进程的格式的过程。在 Node.js 中,序列化被广泛使用:从 REST API 到进程间通信和缓存。在本文中,我们将介绍 Node.js 环境中用于序列化的主要工具和库,以及它们的优缺点。
1. 内置 JSON:事实上的标准
最简单和最流行的方法是使用全局对象 JSON 及其方法 JSON.stringify() 和 JSON.parse()。它在 Node.js 中原生支持,无需安装额外的包。
基本序列化示例:
const user = { name: '阿列克谢', age: 30, roles: ['admin', 'editor'], metadata: null};
// 序列化为字符串const jsonString = JSON.stringify(user);console.log(jsonString);// {"name":"阿列克谢","age":30,"roles":["admin","editor"],"metadata":null}
// 反序列化回对象const parsedUser = JSON.parse(jsonString);console.log(parsedUser.name); // 阿列克谢JSON 的局限性:
- 不支持函数 — 对象的方法将被删除。
- 不支持循环引用 — 会引发错误
Converting circular structure to JSON。 - 忽略 undefined、Symbol、BigInt(后者会引发错误)。
- 将 Date 转换为字符串 — 反序列化时不会恢复为 Date 对象。
使用 replacer 进行自定义序列化:
const data = { name: '测试', date: new Date(), secret: '不保存', nested: { value: 42 }};
const json = JSON.stringify(data, (key, value) => { if (key === 'secret') return undefined; // 排除字段 if (value instanceof Date) return value.toISOString(); // 显式格式化日期 return value;}, 2); // 带缩进的格式化
console.log(json);2. 通过 Buffer 进行序列化:用于二进制数据
当需要传输二进制数据(图像、文件、protobuf)时,使用 Buffer 类。在 Node.js 中,Buffer 允许将字符串和对象转换为二进制格式并恢复。
Buffer 和 JSON 示例:
const obj = { message: '你好,世界!' };
// 序列化为 JSON,然后转换为 Bufferconst buffer = Buffer.from(JSON.stringify(obj), 'utf-8');console.log(buffer); // <Buffer 7b 22 6d 65 73 73 61 67 65 22 3a 22 d0 9f ...
// 恢复const restored = JSON.parse(buffer.toString('utf-8'));console.log(restored.message); // 你好,世界!直接将数字序列化到 Buffer:
const buf = Buffer.alloc(8);buf.writeInt32LE(255, 0); // 写入 32 位整数buf.writeFloatLE(3.14, 4); // 写入 float
console.log(buf); // 二进制表示// 读取console.log(buf.readInt32LE(0)); // 255console.log(buf.readFloatLE(4)); // 3.1400001049041753. flatted 库:循环引用的解决方案
如果您的对象包含循环引用(例如,DOM 树或图),标准 JSON 无法处理。flatted 库(作者:Andrea Giammarchi)解决了这个问题。
安装和示例:
npm install flattedconst { stringify, parse } = require('flatted');
const circularObj = { name: '循环' };circularObj.self = circularObj; // 循环引用
const json = stringify(circularObj);console.log(json);// {"name":"循环","self":"$1"}
const restored = parse(json);console.log(restored.name); // 循环console.log(restored.self === restored); // true