在 JavaScript 中深度克隆对象的最有效方法是什么?原生深度克隆较旧的答案
克隆 JavaScript 对象的最有效方法是什么?我见过被使用,但这是非标准的,只有Firefox支持。
我做过类似的事情,但质疑效率。
我还看到过具有各种缺陷的递归复制函数。
我很惊讶没有规范的解决方案存在。obj = eval(uneval(o));
obj = JSON.parse(JSON.stringify(o));
克隆 JavaScript 对象的最有效方法是什么?我见过被使用,但这是非标准的,只有Firefox支持。
我做过类似的事情,但质疑效率。
我还看到过具有各种缺陷的递归复制函数。
我很惊讶没有规范的解决方案存在。obj = eval(uneval(o));
obj = JSON.parse(JSON.stringify(o));
现在有一个名为“结构化克隆”的JS标准,它在节点11及更高版本中具有实验性工作,将登陆浏览器,并且具有用于现有系统的polyfill。
structuredClone(value)
如果需要,请先加载 polyfill:
import structuredClone from '@ungap/structured-clone';
有关更多详细信息,请参阅此答案。
如果在对象中不使用 s、函数、、、正则表达式、映射、集、Blob、文件列表、图像数据、稀疏数组、类型化数组或其他复杂类型,则用于深度克隆对象的非常简单的一行是:Date
undefined
Infinity
JSON.parse(JSON.stringify(object))
const a = {
string: 'string',
number: 123,
bool: false,
nul: null,
date: new Date(), // stringified
undef: undefined, // lost
inf: Infinity, // forced to 'null'
re: /.*/, // lost
}
console.log(a);
console.log(typeof a.date); // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date); // result of .toISOString()
请参阅Corban的基准测试答案。
由于克隆对象并非易事(复杂类型、循环引用、函数等),因此大多数主要库都提供克隆对象的功能。不要重新发明轮子 - 如果您已经在使用库,请检查它是否具有对象克隆功能。例如
cloneDeep
;可以通过lodash.clonedeep模块单独导入,如果您还没有使用提供深度克隆功能的库,则可能是您的最佳选择angular.copy
jQuery.extend(true, { }, oldObject)
; 仅克隆 DOM 元素.clone()
只是克隆
;零依赖性 npm 模块库的一部分,这些模块只做一件事。适合各种场合的无内疚感公用事业。查看此基准测试:http://jsben.ch/#/bWfk9
在我之前的测试中,速度是我发现的主要问题
JSON.parse(JSON.stringify(obj))
是深度克隆对象的最慢方法(它比 jQuery.extend 慢,标志设置为 true 10-20%)。deep
jQuery.extend在标志设置为(浅克隆)时非常快。这是一个不错的选择,因为它包含一些用于类型验证的额外逻辑,并且不会复制未定义的属性等,但这也会减慢您的速度。deep
false
如果您知道要尝试克隆的对象的结构,或者可以避免深度嵌套数组,则可以编写一个简单的循环来克隆对象,同时检查 hasOwnProperty,这将比 jQuery 快得多。for (var i in obj)
最后,如果您尝试在热循环中克隆已知对象结构,则只需内联克隆过程并手动构造对象,即可获得更高的性能。
JavaScript跟踪引擎在优化循环方面很糟糕,检查ownProperty也会减慢你的速度。当速度是绝对必要的时手动克隆。for..in
var clonedObject = {
knownProp: obj.knownProp,
..
}
在对象上使用该方法时要小心 - 以 ISO 格式返回日期的字符串表示形式,该表示形式不会转换回对象。有关更多详细信息,请参阅此答案。JSON.parse(JSON.stringify(obj))
Date
JSON.stringify(new Date())
JSON.parse()
Date
此外,请注意,至少在Chrome 65中,本机克隆不是要走的路。根据JSPerf的说法,通过创建新函数来执行本机克隆比使用JSON.stringify慢近800倍,JSON.stringify一直都非常快。
如果您使用的是Javascript ES6,请尝试此本机方法来克隆或浅层复制。
Object.assign({}, obj);