v8.serialize()/deserialize() 是 v8 内部二进制序列化接口,非通用深拷贝工具;仅支持 json-like 值(如对象、数组、date、regexp、typedarray 等),不支持函数、原型链、symbol、weakmap、循环引用等。

Node.js 中的 v8.serialize() 和 v8.deserialize() 不是通用深拷贝工具,而是 V8 引擎内部序列化协议的暴露接口,适用于特定场景下的高性能克隆,但有明确限制和前提。
v8.serialize/deserialize 的本质是二进制快照,不是通用深拷贝
这两个方法操作的是 V8 内部的“传输格式”(wire format),它不保留对象原型链、不可枚举属性、访问器属性(getter/setter)、函数、Symbol 键、WeakMap/WeakSet、以及大多数宿主环境对象(如 Buffer、Stream、Promise)。它只支持 JSON-like 的可序列化值:null、undefined、booleans、numbers、strings、arrays、plain objects、Date、RegExp、ArrayBuffer 及其视图(TypedArray)、DataView、BigInt(v14+)、Map、Set(v12.17+)等。
- 函数、class 实例、Error 对象、自定义类实例会被序列化为
null或抛出错误 - 循环引用会直接报错,不支持自动处理
- Buffer 会被正确序列化,但需注意其底层 ArrayBuffer 是否被 transfer(见下文)
基础用法:简单值的无损往返
对纯数据结构(POJO、数组、日期、正则等),可直接使用:
const v8 = require('v8');
const original = {
name: 'Alice',
age: 30,
born: new Date('2000-01-01'),
pattern: /test/gi,
scores: [95, 87, 91]
};
const buffer = v8.serialize(original);
const clone = v8.deserialize(buffer);
console.log(clone.name === original.name); // true
console.log(clone.born.getTime() === original.born.getTime()); // true
console.log(clone.pattern.toString() === original.pattern.toString()); // true
处理 ArrayBuffer 和 TypedArray 的零拷贝转移
当原始数据含大块二进制(如图像、音频 buffer),默认序列化会复制 ArrayBuffer 内容。若需避免内存拷贝,应配合 Serializer 和 Deserializer 手动 transfer:
- 调用
serializer.transferArrayBuffer(id, arrayBuffer)将 ArrayBuffer 标记为“转移”而非复制 - 反序列化时,通过
deserializer.transferArrayBuffer(id, arrayBuffer)恢复同一内存块 - 转移后原 ArrayBuffer 自动变为 detached,不可再访问
这在 Worker 线程间传递大数据时尤为关键,真正实现 C++ 层面的零拷贝共享。
不适用场景与替代建议
若你的对象含以下任一成分,v8.serialize/deserialize 无法胜任:
- 普通 class 实例(非 plain object)——会丢失方法和原型
- 包含函数或闭包的结构
- 含有 WeakMap、FinalizationRegistry 等不可序列化状态的对象
- 需要保留自定义 toJSON/toPrimitive 行为的场景
此时应考虑:
– 对简单结构用 JSON.parse(JSON.stringify())(注意 Date、RegExp、undefined 丢失)
– 对复杂结构用第三方库如 lodash.cloneDeep 或 structuredClone(Node.js v17.0+ 原生支持,更安全且兼容性更好)
– 对极致性能且可控数据结构,可基于 v8.Serializer 子类定制逻辑,跳过不支持类型并注入 fallback 处理
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










