JavaScript 中深度克隆对象的工作原理

介绍

如果您计划使用 JavaScript 进行编码,则需要了解对象的工作原理。对象是 JavaScript 中最重要的元素之一,对对象的深入理解总是有用的。

了解如何在 JavaScript 中正确克隆对象很重要。可以创建对象的浅拷贝和深拷贝。对象的浅拷贝引用原始对象。因此,对原始对象所做的任何更改都将反映在副本中。深拷贝是原始对象所有元素的副本。对原始对象所做的更改不会反映在副本中。在本文中,您将使用Lodash 库创建对象的深层副本

先决条件

要完成本教程,您将需要以下内容:

步骤 1 – 通过重新分配对象创建浅拷贝

如果您创建一个接收对象并更改它的函数,您可能希望创建该对象的副本并更改该副本,而不是更改原始对象。

初始化一个新对象并将其分配给变量testObject这个对象应该具有的信件ab以及c作为键和123为值,分别。

在 JavaScript 中创建对象:

let testObject = {
  a: 1,
  b: 2,
  c: 3
};

现在,尝试通过将 分配给testObject名为 的新变量来创建此对象的副本以进行操作testObjectCopy

let testObject = {
  a: 1,
  b: 2,
  c: 3
};

let testObjectCopy = testObject;

更改键的值atestObject将其设置为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到控制台这是因为创建新变量不会创建副本。相反,它引用了. 您对原始对象所做的任何更改都将反映在假定的副本中,反之亦然。testObjectCopytestObjecttestObjectCopytestObjecttestObject

将对象重新分配给新变量只会创建原始对象的浅拷贝。在下一步中,您将探索循环对象如何成为创建深拷贝的可能解决方案。

步骤 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方法,这不是你复制对象时想要的。这意味着您对原始对象所做的任何更改都将反映在复制的对象中。
  • 如果您的对象具有作为对象的属性,则您复制的对象实际上将引用原始对象,而不是创建实际副本。这意味着如果您更改复制对象中的嵌套对象,原始对象也会更改。
  • 不会复制任何属性描述符。如果您设置类似configurablewritable的内容false,则复制对象中的属性描述符将默认为true

循环对象允许您创建浅拷贝,但不能使用此方法创建深拷贝。值得庆幸的是,有一个库可以提供创建深度副本的解决方案。

第 3 步 – 使用 Lodash 创建浅拷贝和深拷贝

对于只存储数字和字符串等原始类型的简单对象,像上面那样的浅拷贝方法将起作用。但是,如果您的对象具有对其他嵌套对象的引用,则不会复制实际对象。您只会复制参考。

对于深层复制,一个不错的选择是使用可靠的外部库,如LodashLodash 是一个库,它提供了两种不同的功能,允许您进行浅拷贝和深拷贝。这些是cloneclonedeep

要测试 Lodashcloneclonedeep功能,您需要先安装 Lodash:

  • npm install --save lodash

安装 lodash 后,使用该require()函数现在可以访问 Lodash 提供的所有功能:

const  _ = require('lodash');

现在您可以在代码中使用cloneclonedeep函数。创建一个名为 的对象externalObject给出一个animal值为 的'Gator'

const externalObject = {
  animal: 'Gator'
};

创建另一个名为 的对象originalObjectoriginalObject将存储七个具有不同值的属性。属性为,值为 的属性d引用externalObjectanimal'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给新值将同时更改 originalObjectshallowClonedObjectconsole.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 中复制对象一文可以为您指明正确的方向。

觉得文章有用?

点个广告表达一下你的爱意吧 !😁