JavaScript中对象深度克隆的最高效方法
JavaScript中对象深度克隆的最高效方法
技术背景
在JavaScript编程中,对象克隆是一个常见的需求。浅克隆只复制对象的一层属性,而深度克隆会递归地复制对象的所有属性,包括嵌套对象。不同的克隆方法适用于不同的场景,了解它们的优缺点对于编写高效、可靠的代码至关重要。
实现步骤
原生深度克隆
现在所有主流浏览器和Node.js >= 17都支持structuredClone(value)函数,对于旧系统也有polyfills可用。
1 | |
如果需要,可先加载polyfill:
1 | |
不过,该方法有一些限制:
- 函数对象无法通过结构化克隆算法复制,尝试复制会抛出
DataCloneError异常。 - 克隆DOM节点同样会抛出
DataCloneError异常。 - 某些对象属性不会被保留,如
RegExp对象的lastIndex属性、属性描述符、setter、getter等。
有数据丢失的快速克隆 - JSON.parse/stringify
如果对象中不包含Date、函数、undefined、Infinity、RegExp、Map、Set、Blob、FileList、ImageData、稀疏数组、类型化数组或其他复杂类型,可使用JSON.parse(JSON.stringify(object))进行深度克隆。
1 | |
使用库进行可靠克隆
许多主流库都提供了对象克隆的函数,如:
- Lodash -
cloneDeep:如果未使用其他提供深度克隆函数的库,这可能是最佳选择。
1 | |
- Ramda -
clone - AngularJS -
angular.copy - jQuery -
jQuery.extend(true, { }, oldObject) - just library -
just-clone
单行程代码的非深度克隆
Object.assign方法可用于浅克隆对象:
1 | |
对于不支持Object.assign的旧浏览器,可使用以下polyfill:
1 | |
数组的深度克隆
根据数组元素的类型不同,有不同的深度克隆方法:
- 仅包含原始值的数组:可使用扩展运算符
...、slice()、splice(0)、concat()等。
1 | |
- 包含原始值和对象字面量的数组:可使用
JSON.parse(JSON.stringify())。
1 | |
- 包含原始值、对象字面量和原型的数组:可编写自定义函数或使用第三方工具函数。
1 | |
最佳实践
- 如果对象不包含复杂类型,且对性能要求较高,可优先使用
JSON.parse(JSON.stringify())。 - 如果需要处理复杂类型(如
Date、RegExp等),建议使用structuredClone或第三方库(如Lodash的cloneDeep)。 - 在性能敏感的场景下,可编写自定义的克隆函数。
常见问题
JSON.parse(JSON.stringify())的局限性:该方法会丢失Date、函数、undefined、Infinity、RegExp等类型的数据,且不能处理循环引用。Object.assign的浅克隆问题:Object.assign只进行浅克隆,对于嵌套对象,修改原对象的嵌套属性会影响克隆对象。- 结构化克隆的限制:结构化克隆不能复制函数对象和DOM节点,且某些对象属性不会被保留。
JavaScript中对象深度克隆的最高效方法
https://119291.xyz/posts/most-efficient-way-to-deep-clone-object-in-javascript/