在 JS 中,为什么 slice() 文档说它是浅拷贝,而它看起来像深拷贝?

In JS, why does the slice() documentation say it is a shallow copy when it looks like a deep copy?

根据 JavaScript 中 Array.prototype.slice() 的文档,slice() 方法 returns 将数组的一部分浅拷贝到新数组中。据我了解,浅拷贝只会复制数组中的顶级元素,而不会复制嵌套元素。但是,当我 运行 在我的浏览器控制台中进行测试时,看起来 slice() 方法确实在复制嵌套元素(深度复制)。

我哪里误解了深拷贝的概念?请帮我澄清一下,因为它与我的确切示例有关。

var array = [1,2,[3,4,[5,6]]];
var array2 = array.slice();

它正在做一个浅拷贝。但该浅拷贝中的值指向原始 arrays/objects,因为它们是对象引用。

假设我们有:

var orig = [ [1] ];

在记忆中我们有:

                    +−−−−−−−−−−−−−+
[orig:Ref22157]−−−−>|   (array)   |
                    +−−−−−−−−−−−−−+        +−−−−−−−−−−−−−+
                    | 0: Ref84572 |−−−−−−−>|   (array)   |
                    +−−−−−−−−−−−−−+        +−−−−−−−−−−−−−+
                                           | 0: 1        |
                                           +−−−−−−−−−−−−−+

现在我们做:

var copy = orig.slice();

并拥有:

                    +−−−−−−−−−−−−−+
[orig:Ref22157]−−−−>|   (array)   |
                    +−−−−−−−−−−−−−+   
                    | 0: Ref84572 |−−−+
                    +−−−−−−−−−−−−−+   |
                                      |
                                      |    +−−−−−−−−−−−−−+
                                      +−−−>|   (array)   |
                    +−−−−−−−−−−−−−+   |    +−−−−−−−−−−−−−+
[copy:Ref54682]−−−−>|   (array)   |   |    | 0: 1        |
                    +−−−−−−−−−−−−−+   |    +−−−−−−−−−−−−−+
                    | 0: Ref84572 |−−−+
                    +−−−−−−−−−−−−−+

请注意对嵌套数组的引用(此处名义上显示为 "Ref84572",但我们从未看到对象引用的真实值)是如何被复制的,但仍然引用同一个嵌套数组。

这里证明它很肤浅:

var orig = [ [1] ];
var copy = orig.slice();
console.log("orig[0][0] = " + orig[0][0]);
console.log("copy[0][0] = " + copy[0][0]);
console.log("Setting copy[0][0] to 2");
copy[0][0] = 2;
console.log("orig[0][0] = " + orig[0][0]);
console.log("copy[0][0] = " + copy[0][0]);

请注意,当我们修改嵌套数组的状态时,无论我们通过哪条路径到达它(orig[0][0]copy[0][0]),我们都会看到该修改。

slice 是一个浅拷贝,不是因为嵌套值被忽略了,而是因为它们包含对原始数组的引用,因此仍然是链接的。例如:

let arr = [1, [2]]
let shallowCopy = arr.slice(0, arr.length);
shallowCopy[1][0] = "foobar";

// will print "foobar", because the nested array is just a reference
console.log(arr[1][0]);

在这种情况下,浅拷贝意味着嵌套对象将指向原始值。因此,通过修改切片数组中的嵌套对象,您将改变原始对象。

最好看例子:

var originalArray = [1, [2, 3], 4];
var slicedArray = originalArray.slice();
var nestedArray = slicedArray[1]; // [2, 3]
nestedArray.push("oh no, I mutated the original array!");
console.log(originalArray); // [1, [2, 3, "oh no, I mutated the original array!"], 4]