介绍
如果您计划使用 JavaScript 进行编码,则需要了解对象的工作原理。对象是 JavaScript 中最重要的元素之一,对对象的深入理解总是有用的。
了解如何在 JavaScript 中正确克隆对象很重要。可以创建对象的浅拷贝和深拷贝。对象的浅拷贝引用原始对象。因此,对原始对象所做的任何更改都将反映在副本中。深拷贝是原始对象所有元素的副本。对原始对象所做的更改不会反映在副本中。在本文中,您将使用Lodash 库创建对象的深层副本。
先决条件
要完成本教程,您将需要以下内容:
- 您的机器上安装了最新版本的 Node。要安装 Node,请按照此如何安装 Node.js教程中概述的步骤操作。
- 了解如何使用 npm 安装模块和包以及如何配置
package.json
文件。这篇文章如何使用带有 npm 和 package.json 的 Node.js 模块可以帮助你解决这个问题。 - 对 JavaScript 编码的基本理解,您可以在名为“如何用 JavaScript 编码”的系列中找到
步骤 1 – 通过重新分配对象创建浅拷贝
如果您创建一个接收对象并更改它的函数,您可能希望创建该对象的副本并更改该副本,而不是更改原始对象。
初始化一个新对象并将其分配给变量testObject
。这个对象应该具有的信件a
,b
以及c
作为键和1
,2
和3
为值,分别。
在 JavaScript 中创建对象:
let testObject = {
a: 1,
b: 2,
c: 3
};
现在,尝试通过将 分配给testObject
名为 的新变量来创建此对象的副本以进行操作testObjectCopy
:
let testObject = {
a: 1,
b: 2,
c: 3
};
let testObjectCopy = testObject;
更改键的值a
在testObject
。将其设置为9
:
let testObject = {
a: 1,
b: 2,
c: 3
};
let testObjectCopy = testObject;
testObject.a = 9;
您可能期望此更改仅反映在testObject
对象中。使用console.log
语句来检查值a
是什么testObjectCopy
:
let testObject = {
a: 1,
b: 2,
c: 3
};
let testObjectCopy = testObject;
testObject.a = 9;
console.log(testObjectCopy.a);
尽管引用而不是,该console.log
语句仍将打印9
到控制台。这是因为创建新变量不会创建副本。相反,它引用了. 您对原始对象所做的任何更改都将反映在假定的副本中,反之亦然。testObjectCopy
testObject
testObjectCopy
testObject
testObject
将对象重新分配给新变量只会创建原始对象的浅拷贝。在下一步中,您将探索循环对象如何成为创建深拷贝的可能解决方案。
步骤 2 – 通过循环遍历对象创建浅拷贝
循环遍历对象并将每个属性复制到新对象似乎是一个可行的解决方案。为了测试这一点,创建一个名为的函数copyObject
,它接受一个名为 的参数object
:
const copyObject = object => {
};
在 中copyObject
,声明一个名为的变量copiedObj
,它将保存一个空对象:
const copyObject = object => {
let copiedObj = {};
};
for
为 中的每个键创建一个循环object
。将键/值对设置为copiedObj
等于 中的键/值对object
:
const copyObject = object => {
let copiedObj = {};
for (let key in object) {
copiedObj[key] = object[key];
}
};
对于此copyObject
函数的最后一步,返回copiedObj
:
const copyObject = object => {
let copiedObj = {};
for (let key in object) {
copiedObj[key] = object[key];
}
return copiedObj;
};
随着copyObject
到位,创建一个名为对象testObject
,并传递它作为一个参数copyObject
:
const copyObject = object => {
let copiedObj = {};
for (let key in object) {
copiedObj[key] = object[key];
}
return copiedObj;
};
const testObject = {
a: 5,
b: 6,
c: {
d: 4
}
};
copyObject(testObject);
要查看copyObject
函数的结果,请使用打印到控制台console.log
的输出copyObject(testObject)
:
console.log(copyObject(testObject));
这将产生以下输出:
Output{ a: 5, b: 6, c: { d: 4 } }
似乎循环testObject
创建副本产生了所需的结果。但是,这种方法无法为您提供所需结果的原因有多种:
- 将每个属性复制到新对象的循环只会复制对象上的可枚举属性。可枚举属性是将显示在
for
循环和Object.keys
. - 复制的对象有一个新的
Object.prototype
方法,这不是你复制对象时想要的。这意味着您对原始对象所做的任何更改都将反映在复制的对象中。 - 如果您的对象具有作为对象的属性,则您复制的对象实际上将引用原始对象,而不是创建实际副本。这意味着如果您更改复制对象中的嵌套对象,原始对象也会更改。
- 不会复制任何属性描述符。如果您设置类似
configurable
或writable
的内容false
,则复制对象中的属性描述符将默认为true
。
循环对象允许您创建浅拷贝,但不能使用此方法创建深拷贝。值得庆幸的是,有一个库可以提供创建深度副本的解决方案。
第 3 步 – 使用 Lodash 创建浅拷贝和深拷贝
对于只存储数字和字符串等原始类型的简单对象,像上面那样的浅拷贝方法将起作用。但是,如果您的对象具有对其他嵌套对象的引用,则不会复制实际对象。您只会复制参考。
对于深层复制,一个不错的选择是使用可靠的外部库,如Lodash。Lodash 是一个库,它提供了两种不同的功能,允许您进行浅拷贝和深拷贝。这些是clone
和clonedeep
。
要测试 Lodashclone
和clonedeep
功能,您需要先安装 Lodash:
- npm install --save lodash
安装 lodash 后,使用该require()
函数现在可以访问 Lodash 提供的所有功能:
const _ = require('lodash');
现在您可以在代码中使用clone
和clonedeep
函数。创建一个名为 的对象externalObject
。给出一个animal
值为 的键'Gator'
:
const externalObject = {
animal: 'Gator'
};
创建另一个名为 的对象originalObject
。originalObject
将存储七个具有不同值的属性。属性为,值为 的属性d
引用。externalObject
animal
'Gator'
const originalObject = {
a: 1,
b: 'string',
c: false,
d: externalObject
};
创建浅拷贝 clone
声明一个常量变量shallowClonedObject
并将其分配给originalObject
使用 Lodashclone
函数的浅拷贝:
const shallowClonedObject = _.clone(originalObject);
重新分配 中animal
键的值externalObject
。将其设置为'Crocodile'
。使用两个console.log
语句将originalObject
和打印shallowClonedObject
到屏幕:
externalObject.animal = 'Crocodile';
console.log(originalObject);
console.log(shallowClonedObject);
此代码的输出将如下所示:
Output{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
将animal
属性分配externalObject
给新值将同时更改 originalObject
和shallowClonedObject
。该console.log
报告将显示此。发生这种情况是因为浅克隆只能复制对 的引用,externalObject
而不是创建一个全新的对象。
创建深拷贝 clonedeep
你可以使用 Lodashclonedeep
函数创建一个深拷贝:
const deepClonedObject = _.clonedeep(originalObject);
随着deepClonedObject
到位,重新分配的值animal
在关键externalObject
等于'Lizard'
。
同样,使用两个console.log
报表同时打印originalObject
,并deepClonedObject
在屏幕上:
externalObject.animal = 'Lizard';
console.log(originalObject);
console.log(deepClonedObject);
此代码的输出将如下所示:
Output{ a: 1, b: 'string', c: false, d: { animal: 'Lizard' } }
{ a: 1, b: 'string', c: false, d: { animal: 'Crocodile' } }
更改中的'animal'
属性originalObject
,但对于
deepClonedObject
,它仍然是'Crocodile'
因为整个对象是单独复制的,而不是复制引用。使用该clonedeep
函数可以成功创建对象的深层副本。
结论
了解如何在 JavaScript 中深度克隆对象很重要。您通过重新分配和循环对象创建了对象的浅拷贝。您还使用了 Lodash 库来创建对象的浅拷贝和深拷贝。
如果您想了解有关 JavaScript 中对象的更多信息,此了解 JavaScript 中的对象教程是一个很好的起点。如果您想更进一步并学习如何复制对象方法,在 JavaScript 中复制对象一文可以为您指明正确的方向。