在 JavaScript 中深度克隆对象的最有效方法是什么?原生深度克隆较旧的答案

2022-08-29 21:44:59

克隆 JavaScript 对象的最有效方法是什么?我见过被使用,但这是非标准的,只有Firefox支持

我做过类似的事情,但质疑效率。

我还看到过具有各种缺陷的递归复制函数。
我很惊讶没有规范的解决方案存在。obj = eval(uneval(o));obj = JSON.parse(JSON.stringify(o));


答案 1

原生深度克隆

现在有一个名为“结构化克隆”的JS标准,它在节点11及更高版本中具有实验性工作,将登陆浏览器,并且具有用于现有系统的polyfill

structuredClone(value)

如果需要,请先加载 polyfill:

import structuredClone from '@ungap/structured-clone';

有关更多详细信息,请参阅此答案

较旧的答案

快速克隆和数据丢失 - JSON.parse/stringify

如果在对象中不使用 s、函数、、、正则表达式、映射、集、Blob、文件列表、图像数据、稀疏数组、类型化数组或其他复杂类型,则用于深度克隆对象的非常简单的一行是:DateundefinedInfinity

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的基准测试答案。

使用库进行可靠的克隆

由于克隆对象并非易事(复杂类型、循环引用、函数等),因此大多数主要库都提供克隆对象的功能。不要重新发明轮子 - 如果您已经在使用库,请检查它是否具有对象克隆功能。例如


答案 2

查看此基准测试:http://jsben.ch/#/bWfk9

在我之前的测试中,速度是我发现的主要问题

JSON.parse(JSON.stringify(obj))

是深度克隆对象的最慢方法(它比 jQuery.extend 慢,标志设置为 true 10-20%)。deep

jQuery.extend在标志设置为(浅克隆)时非常快。这是一个不错的选择,因为它包含一些用于类型验证的额外逻辑,并且不会复制未定义的属性等,但这也会减慢您的速度。deepfalse

如果您知道要尝试克隆的对象的结构,或者可以避免深度嵌套数组,则可以编写一个简单的循环来克隆对象,同时检查 hasOwnProperty,这将比 jQuery 快得多。for (var i in obj)

最后,如果您尝试在热循环中克隆已知对象结构,则只需内联克隆过程并手动构造对象,即可获得更高的性能。

JavaScript跟踪引擎在优化循环方面很糟糕,检查ownProperty也会减慢你的速度。当速度是绝对必要的时手动克隆。for..in

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

在对象上使用该方法时要小心 - 以 ISO 格式返回日期的字符串表示形式,该表示形式不会转换回对象。有关更多详细信息,请参阅此答案JSON.parse(JSON.stringify(obj))DateJSON.stringify(new Date())JSON.parse()Date

此外,请注意,至少在Chrome 65中,本机克隆不是要走的路。根据JSPerf的说法,通过创建新函数来执行本机克隆比使用JSON.stringify慢近800倍,JSON.stringify一直都非常快。

ES6 的更新

如果您使用的是Javascript ES6,请尝试此本机方法来克隆或浅层复制。

Object.assign({}, obj);