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

时间:2018-01-29 15:43:25

标签: javascript arrays deep-copy

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

enter image description here

我在哪里误解了深层复制的概念?请帮我澄清,因为它与我的确切例子有关。

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

3 个答案:

答案 0 :(得分:5)

它正在做一个浅薄的副本。但是浅拷贝中的值指向原始数组/对象,因为它们是对象引用。

所以,让我们说:

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]),我们都会看到该修改。

答案 1 :(得分:2)

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

最好看一下这个例子:

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]

答案 2 :(得分:1)

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]);