在 JavaScript 中深度克隆对象的最有效方法是什么?

新手上路,请多包涵

克隆 JavaScript 对象的最有效方法是什么?我见过 obj = eval(uneval(o)); 正在使用,但这 是非标准的,仅受 Firefox 支持

我已经完成了 obj = JSON.parse(JSON.stringify(o)); 类的事情。但质疑效率。

我还看到了具有各种缺陷的递归复制函数。

我很惊讶不存在规范的解决方案。

原文由 jschrab 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

本机深度克隆

现在有一个称为 “结构化克隆” 的 JS 标准,它在 Node 11 及更高版本中实验性地工作,将登陆浏览器,并 为现有系统提供 polyfill

 structuredClone(value)

如果需要,首先加载 polyfill:

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

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

较早的答案

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

如果您不使用 Date s、functions、 undefinedInfinity 、RegExps、Maps、Sets、Blobs、FileLists、ImageDatas、sparse Arrays、Typed Arrays 或其他复杂类型在您的对象中,一个非常简单的深度克隆对象的方法是:

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 的答案

使用库进行可靠克隆

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

适合各种场合的无罪实用程序。

原文由 John Resig 发布,翻译遵循 CC BY-SA 4.0 许可协议

检查这个基准:http: //jsben.ch/#/bWfk9

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

JSON.parse(JSON.stringify(obj))

是深度克隆对象的最慢方法(它比 jQuery.extend with deep flag set true 慢 10-20%)。

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

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

最后,如果您试图在热循环中克隆一个已知的对象结构,您可以通过简单地内联克隆过程并手动构造对象来获得更多的性能。

JavaScript 跟踪引擎在优化 for..in 循环和检查 hasOwnProperty 也会减慢你的速度。当绝对需要速度时手动克隆。

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

Beware using the JSON.parse(JSON.stringify(obj)) method on Date objects - JSON.stringify(new Date()) returns a string representation of the date in ISO format, which JSON.parse() doesn’t 转换回 Date 对象。 有关详细信息,请参阅此答案

此外,请注意,至少在 Chrome 65 中,本机克隆不是可行的方法。根据 JSPerf 的说法,通过创建新函数执行本机克隆比使用 JSON.stringify 慢近 800 倍,后者在所有方面都非常快。

ES6 更新

如果您使用的是 Javascript ES6,请尝试使用此本机方法进行克隆或浅拷贝。

 Object.assign({}, obj);

原文由 Corban Brook 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题