浅拷贝含 TypedArray 的对象时,看似成功实则共享底层 ArrayBuffer。因 TypedArray 是视图,浅拷贝仅复制引用,修改副本会同步影响原对象,且 buffer 相等但实例不同;需用 buffer.slice() 或 structuredClone 规避。

浅拷贝在混合普通对象与 TypedArray 的场景下,核心隐患不是“复制失败”,而是“看似成功、实则共享”。关键在于:TypedArray 本身是视图(view),其底层绑定 ArrayBuffer 才是真实内存载体;而普通对象属性若直接赋值该 TypedArray,浅拷贝只复制视图引用,不切断与原 ArrayBuffer 的连接。
TypedArray 视图共享的隐蔽性
TypedArray 实例(如 Uint8Array、Float32Array)不存储数据,只提供对 ArrayBuffer 的类型化读写接口。当你把一个 TypedArray 赋值给对象属性,再对该对象做浅拷贝(如 Object.assign 或展开运算符),副本中的 TypedArray 仍指向**同一个 ArrayBuffer**:
- 修改副本中 TypedArray 的某个元素(如 copy.data[0] = 255),原始对象对应位置同步改变
- 若原始对象后续释放了 ArrayBuffer(如主动 arrayBuffer = null),副本 TypedArray 将变为“死视图”,读写抛错或返回 0
- 这种共享无法通过 === 检测(两个 TypedArray 实例不同),但 buffer 属性相等:original.data.buffer === copy.data.buffer
普通对象嵌套 TypedArray 时的典型误用
常见结构如:{ id: 1, payload: new Uint8Array([1,2,3]) }。使用以下方式浅拷贝均不安全:
- Object.assign({}, obj) —— payload 字段被直接复制,视图未隔离
- {...obj} —— 同上,语法糖本质仍是浅拷贝
- JSON.parse(JSON.stringify(obj)) —— TypedArray 完全丢失(序列化为 {} 或空数组)
结果是:副本修改 payload 会污染原始数据,且无法察觉——因为 payload 本身是独立实例,问题藏在它背后的 buffer。
如何识别与规避共享风险
判断是否发生缓冲区共享,只需检查 buffer 引用:
- 运行时验证:if (original.payload.buffer === copy.payload.buffer) { /* 共享! */ }
- 若需真正隔离,必须显式创建新缓冲区:const newBuf = original.payload.buffer.slice(); const isolatedView = new Uint8Array(newBuf);
- 更高效的做法是复用已有 ArrayBuffer 并重设视图,而非深拷贝整个 TypedArray(避免隐式分配新 buffer)
- 对于含 TypedArray 的对象,不要依赖通用浅拷贝工具;需定制逻辑:对每个 TypedArray 属性单独处理 buffer 复制或视图重映射
与 structuredClone 的对比说明
structuredClone() 是少数能正确处理 TypedArray 的标准方案:它会克隆底层 ArrayBuffer,并生成指向新 buffer 的 TypedArray 视图,实现真正独立。但它不支持函数、undefined 等,且需环境支持(Chrome 98+ / Node.js 18.16+)。若环境受限,手写克隆逻辑必须明确区分普通属性和 TypedArray 属性,对后者执行 buffer.slice() + 新视图构造,而非直接赋值。

















