协慌网

登录 贡献 社区

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

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

我做过像obj = JSON.parse(JSON.stringify(o));但质疑效率。

我也看到了具有各种缺陷的递归复制功能。
我很惊讶没有规范的解决方案。

答案

注意:这是对另一个答案的回复,而不是对此问题的正确回答。如果您希望快速克隆对象,请在回答此问题时遵循Corban 的建议


我想要注意jQuery中的.clone()方法只能克隆 DOM 元素。为了克隆 JavaScript 对象,您可以:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

可以在jQuery 文档中找到更多信息。

我还要注意,深层副本实际上比上面显示的更加智能 - 它可以避免许多陷阱(例如,尝试深度扩展 DOM 元素)。它经常在 jQuery 核心和插件中使用,效果很好。

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

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

JSON.parse(JSON.stringify(obj))

成为深度克隆对象的最快方法(它将jQuery.extend与深度标志设置为 10-20%)。

当深度标志设置为 false(浅层克隆)时,jQuery.extend 非常快。这是一个很好的选择,因为它包含一些额外的类型验证逻辑,不会复制未定义的属性等,但这也会让你慢下来。

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

最后,如果您尝试在热循环中克隆已知对象结构,只需嵌入克隆过程并手动构建对象,即可获得更多性能。

JavaScript 跟踪引擎在优化for..in循环时很for..in并且检查 hasOwnProperty 也会减慢你的速度。当速度是绝对必须时手动克隆。

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

注意在Date对象上使用JSON.parse(JSON.stringify(obj))方法 - JSON.stringify(new Date())返回 ISO 格式的日期的字符串表示形式, JSON.parse() 转换回到Date对象。 有关详细信息,请参阅此答案

此外,请注意,至少在 Chrome 65 中,本机克隆是不可取的。根据这个 JSPerf ,通过创建一个新函数来执行本机克隆比使用 JSON.stringify 慢了近800 倍,而 JSON.stringify 在整个过程中都非常快。

假设您的对象中只有变量而不是任何函数,您可以使用:

var newObject = JSON.parse(JSON.stringify(oldObject));