如何在JavaScript中深度克隆对象

128 阅读5分钟

JavaScript是完全基于对象的,JavaScript中的所有东西都是一个对象。数组是对象,字符串是对象,对象是对象。当你在处理对象或数组时,有时需要复制或克隆一个数组或对象。

有两种类型的对象/数组的克隆,一种是浅层克隆,另一种是深层克隆

为了在vanilla JavaScript中创建深度克隆,我们需要使用JSON parse()函数和JSON stringify()函数的组合。在这篇文章中,我们将讨论什么是浅度克隆和深度克隆,如何在JavaScript中进行克隆,以及如何进行深度克隆。

浅层克隆与深层克隆

当一个包含另一个数组对象的数组对象从一个变量复制到另一个变量时,该数组对象中的元素并没有被复制,而是将一个引用指针复制到新的变量中,该指针指向旧变量。这种复制被称为浅层复制或浅层克隆

而当一个数组对象的元素被直接复制到一个新的变量中时(而不是他们的参考指针),连同嵌套的数组对象,这种复制被称为深层克隆 或深层拷贝。

用JavaScript代码进行解释

这些都是高级的JavaScript概念,这就是为什么我们将使用编码实例来演示浅层克隆和深层克隆的区别。要开始了,使用下面这行代码创建一个包含各种元素的数组。

var originalArray = [true, false, 2, "Google", undefined];

现在,有两种方法可以克隆这个数组。

  • 通过使用分片方法
  • 通过使用传播操作符

要使用切分方法创建一个克隆,请使用下面一行。

var clone1 = originalArray.slice(0);

要使用传播操作符创建一个克隆,请使用下面这行。

var clone2 = [...originalArray];

为了测试我们的元素是否被复制,我们可以使用控制台日志函数来打印出原始数组以及我们的两个克隆。

console.log(originalArray);

console.log(clone1);

console.log(clone2);

我们在控制台得到以下输出。

为了证明这些是真正的克隆,而不是在这些变量中传递的原始数组的引用,我们将在克隆中做一些改变,并检查这些改变是否影响原始数组。

clone1[0] = 1;

clone2[1] = "Hello";

再次将所有的数组打印到控制台,用以下几行来检查这些变化。

console.log(originalArray);

console.log(clone1);

console.log(clone2);

你将观察到以下输出。

正如你所看到的,克隆数组的变化没有影响原始数组,这意味着其他数组没有复制原始数组的引用。

浅层克隆的验证

我们已经看到了如何克隆简单的数组,但是如果我们有一个数组或对象,里面包含了另一个数组,该怎么办,请考虑以下数组。

var originalArray = [["Google"]];

正如你所看到的,我们有一个数组在另一个数组里面,让我们试着用我们在上面的例子中已经使用过的slice方法来克隆这个数组。

var clone = originalArray.slice(0);

我们已经在变量**"clone "中克隆了这个数组,**使用控制台log函数打印出这两个数组。

console.log(originalArray[0]);

console.log(clone[0]);

你应该在屏幕的控制台看到以下结果。

让我们试着用下面这行代码在克隆的数组中做一些改变。

clone[0].push("Maps");

这应该只在**"克隆 "**数组中做出改变,而不是在原始数组中,但这是事情变得有趣的地方。使用控制台日志函数打印出两个数组。

console.log(originalArray[0]);

console.log(clone[0]);

你应该在你的控制台看到以下结果。

你可以很容易地从上面的图片中观察到,克隆的数组中的变化引起了原始数组的变化。这意味着,如果我们的object/array包含了object/array,那么克隆就会传递对嵌套对象的引用,从而形成一个浅层克隆。

Vanilla JavaScript中的深度克隆

呼......仅仅是解释浅层克隆的一个概念,就已经有很多东西了,不过话说回来,这些都是高级别的概念。要使用JavaScript进行深度克隆,有多种方法,但大多数都需要NodeJs。要在vanilla JavaScript中进行深度克隆,你需要使用JSON parse()函数和JSON stringify()函数的组合。用下面这行代码创建一个数组,里面有一个嵌套的数组。

var originalArray = [["Google"]];

使用JSON解析和JSON stringify()的组合,代码如下。

var deepClone = JSON.parse(JSON.stringify(originalArray));

现在,我们已经完成了我们的克隆,我们需要通过使用控制台日志函数将其打印到控制台来验证它。

console.log(clone[0]);

你将在控制台得到以下结果。

现在,让我们试着用下面这行来改变克隆数组的元素。

deepClone[0].push("Maps");

剩下的最后一件事是在控制台观察两个数组,以确定改变克隆数组是否改变了原始数组。

console.log(originalArray[0]);

console.log(deepClone[0]);

你将在控制台得到以下结果。

在上图中,你可以观察到,克隆数组的变化并没有引起原始数组的任何变化。这意味着嵌套的数组/对象也被复制了,而不是将它们的引用传递给新的变量,这就是为什么这种克隆被称为深度克隆。

总结

在vanilla JavaScript中,深度克隆是通过在解析一个新变量中的对象/数组时使用JSON parse()函数和JSON stringify()函数的组合来实现的。在javascript中所有的东西都是一个对象,当我们试图复制嵌套的对象时,它们的引用指针被复制到新的变量中,而不是复制嵌套数组/对象的元素。当一个对象的引用被传递给一个新的对象时,新对象的变化也会导致旧对象的变化,这不是很有效。这就是为什么javascript增加了一种创建深层克隆的方法的原因。