为什么在JavaScript中更改数组会影响数组的副本?

我写了下面的JavaScript:

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray; copyOfMyArray.splice(0, 1); alert(myArray); // alerts ['b','c'] alert(copyOfMyArray); // alerts ['b','c'] var myNumber = 5; var copyOfMyNumber = myNumber; copyOfMyNumber = copyOfMyNumber - 1; alert(myNumber); // alerts 5 alert(copyOfMyNumber); // alerts 4 

这段代码声明了一个variablesmyArray并将其设置为一个数组值。 然后声明第二个variablescopyOfMyArray并将其设置为myArray 。 它对copyOfMyArray执行操作,然后警告myArraycopyOfMyArray 。 不知何故,当我在copyOfMyArray上执行操作时,似乎在myArray上执行相同的操作。

代码然后用一个数字值做同样的事情:它声明一个variablesmyNumber并将其设置为一个数字值。 然后声明第二个variablescopyOfMyNumber并将其设置为myNumber 。 它对copyOfMyNumber执行操作,然后警告myNumbercopyOfMyNumber 。 在这里,我得到了预期的行为: myNumbercopyOfMyNumber值不同。

JavaScript中的数组和数组之间有什么区别,它似乎改变了一个数组改变了一个数组副本的值,其中改变数字不会改变数字副本的值?

我猜测,由于某种原因,数组是通过引用和数值来引用的,但为什么呢? 我怎样才能知道什么行为与其他对象期望?

JavaScript中的数组也是一个对象 ,variables只保存对象的引用 ,而不是对象本身。 因此这两个variables都有一个对同一个对象的引用。

你与数字例子的比较是不正确的顺便说一句。 您将一个新的值分配给copyOfMyNumber 。 如果你给copyOfMyArray指定一个新值,它也不会改变myArray

你可以使用slice [docs]创build一个数组的副本:

 var copyOfMyArray = myArray.slice(0); 

但是请注意,这只返回一个拷贝,即数组内的对象不会被克隆。

那么,唯一可能的答案 – 正确的 – 就是你实际上并没有复制数组。 当你写

 var copyOfArray = array; 

你将一个同一个数组的引用分配给另一个variables。 换句话说,它们都指向同一个对象。

克隆对象 –

一个loop / array.push产生一个类似的结果array.slice(0)array.clone() 。 值都是通过引用传递的,但由于大多数原始数据types是不可变的 ,后续操作会产生所需的结果 – “克隆”。 当然,这对于对象和数组来说并不是这样,它允许修改原始引用(它们是可变types)。

以下面的例子:

 const originalArray = [1, 'a', false, {foor: 'bar'}] const newArray = []; originalArray.forEach((v, i) => { newArray.push(originalArray[i]); }); newArray[0] = newArray[0] + 1; newArray[1] = 'b'; newArray[2] = true; newArray[3] = Object.assign(newArray[3], {bar: 'foo'}); 

在newArray索引上运行的操作都会产生所需的结果,除了最后的(object),因为它是通过引用复制的,所以也会改变originalArray [3]。

https://jsfiddle.net/7ajz2m6w/

请注意, array.slice(0) and array.clone()受到同样的限制。

解决这个问题的一个方法是在推送过程中有效地克隆对象:

 originalArray.forEach((v, i) => { const val = (typeof v === 'object') ? Object.assign({}, v) : v; newArray.push(val); }); 

https://jsfiddle.net/e5hmnjp0/

干杯

所以这里的每个人都做了很好的解释为什么会发生这样的事情 – 我只想放下一条线,让我知道我是如何解决这个问题的 – 很容易:

 thingArray = ['first_thing', 'second_thing', 'third_thing'] function removeFirstThingAndPreserveArray(){ var copyOfThingArray = [...thingArray] copyOfThingArray.shift(); return copyOfThingArray; } 

这是使用…传播语法。

资源

在JS中,运算符“=”将指针复制到数组的内存区域。 如果你想复制一个数组到另一个你必须使用克隆function。

整数是不同的,因为它们是一个原始types。

S.

除原始数据types(string和数字IIRC)外,所有内容都通过引用复制。

您可以根据您的情况添加一些error handling,并使用与以下function类似的内容来解决问题。 请评论任何错误/问题/效率的想法。

 function CopyAnArray (ari1) { var mxx4 = []; for (var i=0;i<ari1.length;i++) { var nads2 = []; for (var j=0;j<ari1[0].length;j++) { nads2.push(ari1[i][j]); } mxx4.push(nads2); } return mxx4; } 

你没有任何副本。
你有多个variables持有相同的数组。

同样,你有多个variables保持相同的数字。

当你写copyOfMyNumber = ... ,你正在把一个新的数字放入variables中。
这就像写copyOfMyArray = ...

当你写copyOfMyArray.splice ,你正在修改原始数组
这是不可能的数字,因为数字是不可改变的,不能修改,

除非您复制或复制,否则JavaScript中的数组或对象始终保持相同的引用。 这里是一个例子:

http://plnkr.co/edit/Bqvsiddke27w9nLwYhcl?p=preview

 // for showing that objects in javascript shares the same reference var obj = { "name": "a" } var arr = []; //we push the same object arr.push(obj); arr.push(obj); //if we change the value for one object arr[0].name = "b"; //the other object also changes alert(arr[1].name); 

对于对象克隆,我们可以在jquery和angular.copy()中使用.clone(),这些函数将创build新的对象与其他引用。 如果你知道更多的function,请告诉我,谢谢!