JS原生深拷贝的终极方案structuredClone用法代码示例

 更新时间:2026年05月27日 11:39:40   作者:代码里的小猫咪  
structuredClone()是JavaScript中用于创建对象深拷贝的原生方法,相比JSON.parse等传统方法,它能更全面地处理复杂数据类型,这篇文章主要介绍了JS原生深拷贝的终极方案structuredClone用法的相关资料,需要的朋友可以参考下

前言

在 JavaScript 开发中,对象的深拷贝一直是一个经典痛点。从 JSON.parse(JSON.stringify()) 的 hack,到 Lodash 的 _.cloneDeep(),开发者们一直在找一个既可靠又高效的深拷贝。2022 年,structuredClone 作为全局 API 正式进入所有主流浏览器和 Node.js,终结了这场漫长的探索。

1. 基本用法

const original = {
  name: 'Alice',
  scores: [95, 87, 92],
  metadata: {
    createdAt: new Date(),
    pattern: /hello/gi,
  },
};

const cloned = structuredClone(original);

cloned.scores.push(100);
console.log(original.scores); // [95, 87, 92] — 互不影响
console.log(cloned.metadata.createdAt instanceof Date); // true — 类型保留
console.log(cloned.metadata.pattern instanceof RegExp); // true

一行代码,深拷贝完成。没有序列化/反序列化的中间步骤,没有第三方依赖。

Transfer 参数

structuredClone 的第二个参数支持 transfer 选项,这是它相比其他深拷贝方案的独特能力:

const buffer = new ArrayBuffer(1024 * 1024 * 100); // 100MB

// 传统克隆:复制 100MB 内存
const cloned = structuredClone(buffer);

// Transfer:所有权转移,零拷贝
const transferred = structuredClone(buffer, { transfer: [buffer] });

console.log(buffer.byteLength); // 0 
console.log(transferred.byteLength); // 104857600

Transfer 的本质是所有权转移(ownership transfer),不是复制。底层只是修改了内存区域的归属指针,时间复杂度 O(1)。

为什么要这样设计?

核心原因是性能。如果要把 100MB 的视频帧数据发给 Web Worker 处理:

// 方式 1:复制(慢,瞬间多占 100MB 内存)
worker.postMessage(buffer);

// 方式 2:转移(瞬间完成,内存不增长)
worker.postMessage(buffer, [buffer]);
// 但此后主线程不能再用这个 buffer 了

Transfer 的代价是:原始变量变成一个"空壳"(规范称为 detached / neutered)。这是一个权衡——用"独占访问权"换来了"零拷贝性能"。

2. 支持/行为

这是 structuredClone 最大的优势所在。

  • 支持:普通对象、数组、Date、Map、Set、RegExp、ArrayBuffer、TypedArray、Blob、File、BigInt、循环引用等
  • 不支持/会报 DataCloneError(典型):
    • function,函数闭包绑定了执行上下文,无法序列化
    • WeakMap/WeakSet,弱引用语义不允许枚举
    • Proxy(Vue reactive 就在这)
    • DOM Nodes,绑定了渲染树,跨上下文无意义
  • 保留对象图结构:可保留“同一引用关系”和循环结构

关键:原型链丢失

class Vector {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  magnitude() {
    return Math.sqrt(this.x ** 2 + this.y ** 2);
  }
}

const v = new Vector(3, 4);
const cloned = structuredClone(v);

console.log(cloned.x); // 3
console.log(cloned.magnitude); // undefined 
console.log(Object.getPrototypeOf(cloned) === Vector.prototype); // false
console.log(Object.getPrototypeOf(cloned) === Object.prototype); // true

structuredClone 克隆的是数据,不是行为

对比 JSON.parse(JSON.stringify()) 支持/行为

  • 支持:普通对象、数组、字符串、数字、布尔、null
  • 会丢失/变化:
    • undefined(对象属性会被丢弃)
    • function(丢弃)
    • symbol(丢弃)
    • Date -> 字符串(ISO)
    • Map/Set -> 通常变空对象或丢信息
    • RegExp -> 普通对象/空对象
    • NaN/Infinity/-Infinity -> null
    • BigInt -> 直接报错(TypeError)
  • 循环引用:直接报错 Converting circular structure to JSON

循环引用

这是 structuredClone 相比 JSON 方案的核心优势之一:

const obj = { name: 'root' };
obj.self = obj;
obj.children = [{ parent: obj }];

// JSON 方案直接爆炸
// JSON.stringify(obj); // TypeError: Converting circular structure to JSON

// structuredClone 优雅处理
const cloned = structuredClone(obj);
console.log(cloned.self === cloned); // true
console.log(cloned.children[0].parent === cloned); // true
console.log(cloned !== obj); // true 

算法内部维护了一个 (source, clone) 的映射表。当遍历到已经克隆过的对象时,直接返回映射表中的克隆体,从而:

  • 避免无限递归
  • 保持引用拓扑结构的一致性

3. 底层原理

JSON 方案底层原理

JSON.stringify(ECMAScript JSON 序列化算法)做的事:

  • 遍历对象可序列化属性
  • 处理 toJSON(如 Date 会先转字符串)
  • 生成 JSON 文本(UTF-16 JS 字符串)

JSON.parse 做的事:

  • 词法/语法解析 JSON 文本
  • 构建全新 JS 对象树
  • 可选 reviver 二次转换

本质:文本协议往返

structuredClone 底层原理

基于 HTML 标准里的 Structured Clone Algorithm(浏览器/运行时实现):

  • 从源对象图开始遍历
  • 维护“已访问对象表”(解决循环与共享引用
  • 按对象类型走不同克隆分支(Map/Set/Date/TypedArray 等)
  • 生成克隆对象图并重建引用关系
  • 可选 transfer 列表:对可转移对象“转移所有权”(原对象 detach)

本质:对象图语义复制(不是文本)。

4. 一句话总结

1、JSON.parse(JSON.stringify(obj)):本质是先序列化成 JSON 文本,再解析回对象,是“文本中转”。

2、structuredClone(obj):本质是按结构化克隆算法直接复制内存对象图,不是 JSON 文本中转。

附:structuredClone () 与其他克隆方法详细对比

与 JSON.parse (JSON.stringify ()) 对比

在 JavaScript 中,JSON.parse(JSON.stringify()) 是一种常用的实现深拷贝的方法,但它与 structuredClone() 存在诸多差异。

在支持的数据类型方面,JSON.parse(JSON.stringify()) 仅支持基本数据类型(如数字、字符串、布尔值)、普通对象和数组 。对于 Date 对象,它会将其转换为字符串,在反序列化后不再是 Date 对象,而是普通字符串;Map、Set、RegExp 对象会被转换为空对象;函数、undefined、symbol、Infinity、NaN 以及循环引用等都无法正确处理 。而 structuredClone() 支持的数据类型更为广泛,除了基本数据类型和普通对象、数组外,还支持 Date、RegExp、Map、Set、ArrayBuffer、TypedArrays、Blob、File、ImageData、MessagePort 等,并且能正确处理循环引用 。例如:

// JSON.parse(JSON.stringify()) 处理不支持的类型
const original1 = {
date: new Date(),
map: new Map([['key1', 'value1']]),
func: function() { return 'function' }
};
const jsonClone1 = JSON.parse(JSON.stringify(original1));
console.log(jsonClone1.date instanceof Date); // false,Date 被转为字符串
console.log(jsonClone1.map instanceof Map); // false,Map 被转为空对象
console.log(jsonClone1.func); // undefined,函数丢失
// structuredClone() 处理支持的类型
const original2 = {
date: new Date(),
map: new Map([['key1', 'value1']]),
arrayBuffer: new Uint8Array([1, 2, 3]).buffer
};
const structuredClone2 = structuredClone(original2);
console.log(structuredClone2.date instanceof Date); // true
console.log(structuredClone2.map instanceof Map); // true
console.log(structuredClone2.arrayBuffer instanceof ArrayBuffer); // true

在循环引用处理上,JSON.parse(JSON.stringify()) 无法处理对象中的循环引用,当对象存在循环引用时,调用 JSON.stringify() 会抛出 TypeError: Converting circular structure to JSON 错误 ,导致克隆失败。而 structuredClone() 可以正确处理循环引用,确保克隆后的对象包含正确的循环引用结构,不会陷入无限循环 。比如:

// JSON.parse(JSON.stringify()) 处理循环引用
let obj1 = {};
let obj2 = { ref: obj1 };
obj1.ref = obj2;
try {
const jsonClone = JSON.parse(JSON.stringify(obj1));
} catch (error) {
console.error('JSON.parse(JSON.stringify())循环引用错误:', error); // 抛出错误
}
// structuredClone() 处理循环引用
let obj3 = {};
let obj4 = { ref: obj3 };
obj3.ref = obj4;
const structuredClone3 = structuredClone(obj3);
console.log(structuredClone3.ref === structuredClone3.ref.ref); // true,循环引用处理正确

性能方面,JSON.parse(JSON.stringify()) 在处理简单的、JSON 兼容的数据结构时性能尚可,但在处理复杂对象或包含大量非 JSON 兼容类型的数据时,由于需要进行序列化和反序列化操作,效率较低 。structuredClone() 是为深度克隆设计的原生方法,内部针对复杂场景进行了优化,通常在处理复杂对象时性能更优 。通过以下测试可以明显看出两者的性能差异:

// 性能测试
const largeArray = new Array(10000).fill({ key: 'value' });
console.time('JSON.parse(JSON.stringify())');
const jsonClone = JSON.parse(JSON.stringify(largeArray));
console.timeEnd('JSON.parse(JSON.stringify())');
console.time('structuredClone');
const structuredClone4 = structuredClone(largeArray);
console.timeEnd('structuredClone');

在浏览器兼容性上,JSON.parse(JSON.stringify()) 在现代浏览器和较旧的浏览器中都有广泛支持 。而 structuredClone() 是一种较新的 API,在某些较旧的浏览器中不被支持 ,使用时需要考虑兼容性问题,可以通过检测 typeof structuredClone === 'function' 来判断浏览器是否支持该方法,不支持时可采用其他替代方案。

到此这篇关于JS原生深拷贝的终极方案structuredClone用法代码示例的文章就介绍到这了,更多相关JS原生深拷贝structuredClone内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 通过js控制修改css变量的具体示例

    通过js控制修改css变量的具体示例

    在网页开发中我们通常使用CSS来设置网页的样式,但是,在开发过程中,有时候我们需要根据不同的条件来动态修改样式,这篇文章主要介绍了通过js控制修改css变量的具体示例,需要的朋友可以参考下
    2025-04-04
  • es7中的async、await使用方法示例详解

    es7中的async、await使用方法示例详解

    async、await是es7里面的新语法,async申明一个function是异步,而await等待一个异步方法执行完成。替代promise中的then。async函数返回一个Promise对象,当函数执行的时候,一旦遇到await就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。
    2023-01-01
  • javascript基于prototype实现类似OOP继承的方法

    javascript基于prototype实现类似OOP继承的方法

    这篇文章主要介绍了javascript基于prototype实现类似OOP继承的方法,实例分析了JavaScript使用prototype实现面向对象程序设计的中类继承的相关技巧,需要的朋友可以参考下
    2015-12-12
  • 微信小程序实现通过双向滑动缩放图片大小的方法

    微信小程序实现通过双向滑动缩放图片大小的方法

    这篇文章主要介绍了微信小程序实现通过双向滑动缩放图片大小的方法,结合实例形式分析了微信小程序事件响应及图片元素属性动态操作相关实现技巧,需要的朋友可以参考下
    2018-12-12
  • BootStrap表单控件之文本域textarea

    BootStrap表单控件之文本域textarea

    这篇文章主要介绍了BootStrap表单控件之文本域textarea,需要的朋友可以参考下
    2017-05-05
  • javascript实现自由编辑图片代码详解

    javascript实现自由编辑图片代码详解

    这篇文章主要介绍了javascript实现自由编辑图片代码详解,在当下的的前端项目中,图片功能可以说是非常常见的,图片的展示、图片的裁剪编辑、图片的上传等,那么我们的项目便来了个需求。,需要的朋友可以参考下
    2019-06-06
  • JavaScript列表框listbox全选和反选的实现方法

    JavaScript列表框listbox全选和反选的实现方法

    这篇文章主要介绍了JavaScript列表框listbox全选和反选的实现方法,涉及javascript操作列表框listbox的技巧,非常具有实用价值,需要的朋友可以参考下
    2015-03-03
  • JavaScript定义和初始化二维数组的三种常用方法

    JavaScript定义和初始化二维数组的三种常用方法

    这篇文章主要介绍了在 JavaScript 中定义和初始化二维数组的三种常用方法,并通过示例代码和实际应用场景进行解释,帮助开发者深入理解其使用技巧和注意事项,需要的朋友可以参考下
    2025-12-12
  • JS DOM 操作实现代码

    JS DOM 操作实现代码

    JS DOM 操作实现代码,学习dom操作的朋友可以参考下。
    2010-08-08
  • js实现拖拽上传图片功能

    js实现拖拽上传图片功能

    这篇文章主要为大家详细介绍了js实现拖拽上传图片功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08

最新评论