[译文]如何用JavaScript克隆一个对象
JavaScript对象是键值对的集合。它是一种可以包含各种数据类型的非原生的数据类型。
1 | const userDetails = { |
在 JavaScript 中使用对象时,有时你可能想要更改值或向对象添加新属性。
在某些情况下,在更新或添加新属性之前,你会希望创建一个新对象并复制或克隆原始对象的值。
例如,如果你想复制 userDetails 对象的值,然后修改 name 属性的值。此时,你会使用赋值 (=) 运算符。
1 | const newUser = userDetails; |
一切看起来都正常,但是当我们修改一下新对象,看看会发生什么?
1 | const newUser = userDetails; |
结果就是原始对象 userDetails 的值也受到了影响,因为对象是引用类型。
这意味着存储在新对象或原始对象中的任何值都指向同一个对象。
这不是你想要的。你希望将一个对象的值存储在一个新对象中,并在不影响原始对象的情况下操作新对象中的值。
在本文中,你将学习三种可用于执行此操作的方法。你还将了解深克隆和浅克隆的含义以及它们的工作原理。
如果你赶时间,以下有三种方法和它们的例子。
1 | // Spread Method |
如果你不赶时间,让我们开始吧。
如何使用扩展运算符在 JavaScript 中克隆对象#
扩展运算符是在 ES6 中引入的,可以将值扩展到三个点前面的对象中。
1 | // Declaring Object |
这不再被引用,这意味着更改新对象的值不会影响原始对象。
1 | // Cloning the Object with Spread Operator |
当你检查原始对象的 name 属性或整个对象中的值时,你会注意到它没有受到影响。
注意:当遇到深对象时,扩展运算符只能对对象进行浅拷贝,当你读完本文你就会明白了。
如何使用 Object.assign() 在 JavaScript 中克隆对象#
扩展运算符的替代方法是 Object.assign() 方法。你可以使用此方法将值和属性从一个或多个源对象复制到目标对象。
1 | // Declaring Object |
这不再被引用,这意味着更改新对象的值不会影响原始对象。
1 | // Cloning the Object with Object.assign() Method |
当你检查原始对象的 name 属性或整个对象中的值时,你会注意到它没有受到影响。
注意:当遇到深对象时,Object.assign() 方法只能对对象进行浅拷贝,当你读完本文你就会明白了。
如何使用 JSON.parse() 在 JavaScript 中克隆对象#
最后一个方法是 JSON.parse()。你将结合JSON.stringify() 一起使用。
你可以使用它来深度克隆,但它有一些缺点。
首先,让我们看看它是如何工作的。
1 | // Declaring Object |
就像前面的方法一样,新的对象不再引用它。这意味着你可以在不影响原始对象的情况下更改新对象中的值。
1 | // Cloning the Object with JSON.parse() Method |
当你检查原始对象的 name 属性或整个对象中的值时,你会注意到它没有受到影响。
注意:此方法可用于深度克隆,但不是最佳选择,因为它不适用于function或symbol属性。
现在让我们探讨浅克隆和深度克隆,以及如何使用该JSON.parse()方法执行深度克隆。你还将了解为什么它不是最佳的选择。
浅克隆与深克隆#
到目前为止,本文使用的示例是一个只有一层的基础对象。
这意味着我们只执行了浅克隆。
但是当一个对象有多于一层时,你就需要进行深度克隆。
1 | // Shallow object 浅对象 |
注意,深对象不止一层,因为 userDetails 对象中还有另外一个对象。
一个深对象可以有任意多的层次。
注意:当你使用扩展操作符或Object.assign()方法克隆一个深对象时,更深的对象将引用。
1 | const userDetails = { |
你会注意到原始对象和新对象都会受到影响,因为当你使用扩展运算符或Object.assign()方法克隆深对象时,将引用更深的对象。
你怎么解决这个问题#
你可以使用JSON.parse()方法,一切都会正常进行。
1 | const userDetails = { |
但是这种方法有一个问题 —— 就是你可能会丢失数据。
正如以上的例子显示的那样,JSON.stringify()与数字、字符串或布尔值等原生的数据类型配合得很好。
相对应的,当遇到非原生的数据类型时,JSON.stringify()方法出现意想不到的结果。
例如,当属性的值为:Nan、Infinityto、null、undefined、Symbol、object等类型是,JSON.stringify()方法会返回一个空的键值对并跳过它。
1 | const userDetails = { |
JSON.stringify() 将不会返回值为 Symbol 和 undefined 的键值对。
1 | console.log(cloneUser); |
这意味着你需要小心。实施深克隆的最佳选择是使用 Lodash。
这样你就可以确定你的任何数据都不会丢失。
1 | const userDetails = { |
总结#
本文介绍了如何使用三种主要方法在 JavaScript 中克隆对象。
你已经了解了这些方法的工作原理,以及何时使用每种方法。
你还了解了深度克隆。
你可以阅读本文以了解为什么JSON.parse(JSON.stringify())在 JavaScript 中克隆对象是一种不好的做法。