介绍
如果你计划使用JavaScript编码,你需要了解对象是如何工作的。
重要的是要了解如何正确地克隆JavaScript中的对象。 可以创建一个浅副本和一个深副本的对象。 一个浅副本引用了原始对象,所以对原始对象所做的任何更改都会反映在副本中。 一个深副本是原始对象的所有元素的副本。 对原始对象所做的任何更改不会反映在副本中。 在本文中,您将使用Lodash库创建对象的深副本。
前提条件
要完成本教程,您将需要以下内容:
- 最新版本的 Node 安装在您的计算机上. 要安装 Node,请遵循本教程中描述的步骤(How To Install Node.js)(https://www.digitalocean.com/community/tutorial_collections/how-to-install-node-js)教程
- 了解如何使用 npm 安装模块和包,以及如何配置
package.json
文件。 本文(如何使用 Node.js 模块与 npm 和 package.json)(https://andsky.com/tech/tutorials/how-to-use-node-js-modules-with-npm-and-package-json)可以帮助您解决此问题 - 您可以在本系列中找到的 JavaScript 编码的基本理解,名为 How to Code in JavaScript
步骤 1 – 通过重新分配对象创建 Shallow 副本
如果您创建一个包含对象并更改该对象的函数,则可能需要创建对象的副本并更改副本,而不是突变原始对象。
初始化一个新对象,并将其分配到变量testObject
中,该对象应有字母a
,b
和c
作为键,以及1
,2
和3
作为值。
在 JavaScript 中创建对象:
1let testObject = {
2 a: 1,
3 b: 2,
4 c: 3
5};
现在,尝试通过将testObject
分配给一个名为testObjectCopy
的新变量来创建该对象的副本来操纵:
1let testObject = {
2 a: 1,
3 b: 2,
4 c: 3
5};
6
7let testObjectCopy = testObject;
在testObject
中更改a
键的值,将其设置为9
:
1let testObject = {
2 a: 1,
3 b: 2,
4 c: 3
5};
6
7let testObjectCopy = testObject;
8
9testObject.a = 9;
您可以期望此更改仅反映在testObject
对象中。 使用console.log
语句来检查testObjectCopy
中的a
值是什么:
1let testObject = {
2 a: 1,
3 b: 2,
4 c: 3
5};
6
7let testObjectCopy = testObject;
8
9testObject.a = 9;
10console.log(testObjectCopy.a);
此console.log
声明将打印9
到控制台,尽管引用testObjectCopy
,而不是testObject
。 这是因为创建新的变量testObjectCopy
不会创建testObject
副本,而是引用testObject
。
将对象重新分配给新的变量只会创建原始对象的浅副本. 在下一步中,您将探索通过对象循环是如何创建深副本的可能解决方案。
步骤 2 – 通过环绕对象创建 Shallow 副本
浏览对象并将每个属性复制到一个新的对象似乎是一个可行的解决方案. 要测试这一点,请创建一个名为copyObject
的函数,该函数采用一个名为object
的参数:
1const copyObject = object => {
2
3};
在copyObject
中,声明一个名为copiedObj
的变量,该变量将包含一个空的对象:
1const copyObject = object => {
2
3 let copiedObj = {};
4};
在object
中为每个键创建一个for
循环. 将copiedObj
中的关键/值对等于object
中的关键:
1const copyObject = object => {
2 let copiedObj = {};
3
4 for (let key in object) {
5 copiedObj[key] = object[key];
6 }
7};
对于这个copyObject
函数的最后一步,返回copiedObj
:
1const copyObject = object => {
2 let copiedObj = {};
3
4 for (let key in object) {
5 copiedObj[key] = object[key];
6 }
7
8 return copiedObj;
9};
有了copyObject
,创建一个名为testObject
的对象,然后将其传输为copyObject
的参数:
1const copyObject = object => {
2
3 let copiedObj = {};
4
5 for (let key in object) {
6 copiedObj[key] = object[key];
7 }
8
9 return copiedObj;
10};
11
12const testObject = {
13 a: 5,
14 b: 6,
15 c: {
16 d: 4
17 }
18};
19
20copyObject(testObject);
若要查看copyObject
函数的结果,请使用console.log
查看在控制台上打印的copyObject(testObject)
的输出:
1console.log(copyObject(testObject));
这将产生这样的产量:
1[secondary_label Output]
2{ a: 5, b: 6, c: { d: 4 } }
它可能看起来像是通过testObject
循环创建一个副本产生了所需的结果,但有几个原因,为什么这种方法不会给你你正在寻找的结果:
- 将每个属性复制到新对象的循环只会复制可编号的属性在对象上。 _ 可编号的属性_是将出现在
for
循环和Object.keys
中的属性 *复制对象有一个新的Object.prototype
方法,而不是你在复制对象时想要的属性。这意味着你对原始对象所做的任何更改都会反映在复制对象中 - 如果你的对象有一个属性是对象,那么你的复制对象实际上将指向原始而不是创建实际副本。
通过对象旋转可以创建浅副本,但无法使用此方法创建深副本. 幸运的是,有一个库可提供创建深副本的解决方案。
步骤 3 – 使用 Lodash 创建 Shallow 和 Deep 副本
对于仅存储原始类型(如数字和字符串)的简单对象,如上面的复制方法将奏效,但是,如果您的对象具有与其他嵌入对象的引用,则实际对象不会被复制。
对于深度复制,一个很好的选择是使用可靠的外部库,如 Lodash。Lodash是一个提供两个不同的功能的库,允许您进行浅层复制和深层复制。
要测试Lodash的克隆
和克隆
功能,您需要先安装Lodash:
1npm install --save lodash
现在安装了 lodash,使用require()
函数现在可以访问Lodash提供的所有功能:
1const _ = require('lodash');
现在你可以在你的代码中使用克隆
和克隆
函数,创建一个名为externalObject
的对象,给一个具有Gator
值的动物
密钥:
1const externalObject = {
2 animal: 'Gator'
3};
创建另一个名为originalObject
的对象,originalObject
将存储7个具有不同值的属性,每个属性d
是指具有动物
属性和Gator
值的外部Object
。
1const originalObject = {
2 a: 1,
3 b: 'string',
4 c: false,
5 d: externalObject
6};
使用克隆
创建 Shallow 副本
声明恒定变量shallowClonedObject
,并使用Lodash克隆
函数将其分配给原始Object
的浅副本:
1const shallowClonedObject = _.clone(originalObject);
在externalObject
中重新分配动物
键值,将其设置为Crocodile
。 使用两个console.log
语句将originalObject
和shallowClonedObject
打印到屏幕上:
1externalObject.animal = 'Crocodile';
2
3console.log(originalObject);
4console.log(shallowClonedObject);
这个代码的输出将是这样的:
1[secondary_label Output]
2{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
3{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
将外部对象
中的动物
属性分配到一个新的值将改变原始对象
和shallowClonedObject
。
使用clonedeep
创建深度副本
您可以使用Lodash clonedeep
函数创建深度副本:
1const deepClonedObject = _.clonedeep(originalObject);
當「deepClonedObject」位於位置時,將「外部Object」中的「動物」鍵的值重新分配為「Lizard」。
再次,使用两个console.log
语句将originalObject
和deepClonedObject
打印到屏幕上:
1externalObject.animal = 'Lizard';
2
3console.log(originalObject);
4console.log(deepClonedObject);
这个代码的输出将是这样的:
1[secondary_label Output]
2{ a: 1, b: 'string', c: false, d: { animal: 'Lizard' } }
3{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
原始对象中的动物
属性发生变化,但对于
深克隆对象
,它仍然是鳄鱼
,因为整个对象被单独复制而不是复制引用。
结论
了解如何在JavaScript中深度克隆对象很重要,您通过重新分配和循环对象来创建对象的浅副本,您还使用了Lodash库创建对象的浅和深副本。
如果你想了解更多关于对象的JavaScript,这个 理解对象的JavaScript教程是一个很好的开始的地方。