为什么在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
执行操作,然后警告myArray
和copyOfMyArray
。 不知何故,当我在copyOfMyArray
上执行操作时,似乎在myArray
上执行相同的操作。
代码然后用一个数字值做同样的事情:它声明一个variablesmyNumber
并将其设置为一个数字值。 然后声明第二个variablescopyOfMyNumber
并将其设置为myNumber
。 它对copyOfMyNumber
执行操作,然后警告myNumber
和copyOfMyNumber
。 在这里,我得到了预期的行为: myNumber
和copyOfMyNumber
值不同。
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,请告诉我,谢谢!