为什么在 JavaScript 中更改数组会影响数组的副本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6612385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does changing an Array in JavaScript affect copies of the array?
提问by Vivian River
I've written the following 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
This code declares a variable myArray
and sets it to an array value. It then declares a second variable copyOfMyArray
and sets it to myArray
.
It performs an operation on copyOfMyArray
and then alerts both myArray
and copyOfMyArray
. Somehow, when I perform an operation on copyOfMyArray
, it appears that the same operation is performed on myArray
.
此代码声明一个变量myArray
并将其设置为数组值。然后它声明了第二个变量copyOfMyArray
并将其设置为myArray
. 它对 和 执行操作copyOfMyArray
,然后向myArray
和发出警报copyOfMyArray
。不知何故,当我对 执行操作时copyOfMyArray
,似乎对 执行了相同的操作myArray
。
The code then does the same thing with a number value: It declares a variable myNumber
and sets it to a number value. It then declares a second variable copyOfMyNumber
and sets it to myNumber
. It performs an operation on copyOfMyNumber
and then alerts both myNumber
and copyOfMyNumber
. Here, I get the expected behavior: different values for myNumber
and copyOfMyNumber
.
然后代码对数字值做同样的事情:它声明一个变量myNumber
并将它设置为一个数字值。然后它声明了第二个变量copyOfMyNumber
并将其设置为myNumber
. 它对 和 执行操作copyOfMyNumber
,然后向myNumber
和发出警报copyOfMyNumber
。在这里,我得到预期的行为:对不同的价值观myNumber
和copyOfMyNumber
。
What is the difference between an array and a number in JavaScript that it seems changing an array changes the value of a copy of the array, where as changing a number does not change the value of a copy of the number?
JavaScript 中的数组和数字之间有什么区别,似乎更改数组会更改数组副本的值,而更改数字不会更改数字副本的值?
I'm guessing that for some reason, the array is referred to by reference and the number by value, but why? How can I know what behavior to expect with other objects?
我猜出于某种原因,数组是通过引用引用的,而数字是通过值引用的,但为什么呢?我如何知道其他对象的预期行为?
回答by Felix Kling
An array in JavaScript is also an objectand variables only hold a referenceto an object, not the object itself. Thus both variables have a reference to the sameobject.
JavaScript 中的数组也是一个对象,变量只保存对对象的引用,而不是对象本身。因此,两个变量都有对同一个对象的引用。
Your comparison with the number example is not correct btw. You assign a new value to copyOfMyNumber
. If you assign a new value to copyOfMyArray
it will not change myArray
either.
顺便说一句,您与数字示例的比较不正确。您为 分配了一个新值copyOfMyNumber
。如果您为其分配一个新值,copyOfMyArray
它也不会改变myArray
。
You can create a copy of an array using slice
[docs]:
您可以使用slice
[docs]创建数组的副本:
var copyOfMyArray = myArray.slice(0);
But note that this only returns a shallowcopy, i.e. objects inside the array will not be cloned.
但请注意,这仅返回浅拷贝,即不会克隆数组内的对象。
回答by Pointy
Well, the only possible answer — and the correct one — is that you're not actually copying the array.When you write
好吧,唯一可能的答案——也是正确的答案——是你实际上并没有复制数组。当你写
var copyOfArray = array;
you're assigning a referenceto the same array into another variable. They're both pointing at the same object, in other words.
您将对同一数组的引用分配给另一个变量。换句话说,它们都指向同一个对象。
回答by Salvatore
So everyone here has done a great job of explaining whythis is happening - I just wanted to drop a line and let you know howI was able to fix this - pretty easily:
所以这里的每个人都很好地解释了为什么会发生这种情况——我只是想留下一条线,让你知道我是如何解决这个问题的——很容易:
thingArray = ['first_thing', 'second_thing', 'third_thing']
function removeFirstThingAndPreserveArray(){
var copyOfThingArray = [...thingArray]
copyOfThingArray.shift();
return copyOfThingArray;
}
This is using the ... spread syntax.
这是使用...传播语法。
EDIT: As to the whyof this, and to answer your question:
编辑:至于为什么会这样,并回答您的问题:
What is the difference between an array and a number in JavaScript that it seems changing an array changes the value of a copy of the array, where as changing a number does not change the value of a copy of the number?
JavaScript 中的数组和数字之间有什么区别,似乎更改数组会更改数组副本的值,而更改数字不会更改数字副本的值?
The answer is that in JavaScript, arrays and objects are mutable, while strings and numbers and other primitives are immutable. When we do an assignment like:
答案是在 JavaScript 中,数组和对象是可变的,而字符串和数字以及其他原语是不可变的。当我们做这样的任务时:
var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;
var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;
copyOfMyArray is really just a reference to myArray, not an actual copy.
copyOfMyArray 实际上只是对 myArray 的引用,而不是实际的副本。
I would recommend this article, What are immutable and mutable data structures?, to dig deeper into the subject.
我会推荐这篇文章,什么是不可变和可变数据结构?, 深入研究该主题。
回答by Bosworth99
Cloning objects -
克隆对象 -
A loop / array.push
produces a similar result to array.slice(0)
or array.clone()
. Values are all passed by reference, but since most primitive data types are immutable, subsequent operations produce the desired result - a 'clone'. This is not true of objects and arrays, of course, which allow for modification of the original reference (they are mutable types).
Aloop / array.push
产生与array.slice(0)
或类似的结果array.clone()
。值都是通过引用传递的,但由于大多数原始数据类型是不可变的,后续操作会产生所需的结果 - 一个“克隆”。当然,对象和数组不是这样,它们允许修改原始引用(它们是可变类型)。
Take the following example:
以下面的例子为例:
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'});
The operations run on the newArray indices all produce the desired result, except the final (object), which, because it is copied by reference, will mutate the originalArray[3] as well.
在 newArray 索引上运行的操作都会产生所需的结果,除了最终(对象),因为它是通过引用复制的,所以也会改变 originalArray[3]。
https://jsfiddle.net/7ajz2m6w/
https://jsfiddle.net/7ajz2m6w/
Note that array.slice(0)
and array.clone()
suffers from this same limitation.
请注意,它也array.slice(0)
and array.clone()
受到同样的限制。
One way to solve this is by effectively cloning the object during the push sequence:
解决此问题的一种方法是在推送序列期间有效地克隆对象:
originalArray.forEach((v, i) => {
const val = (typeof v === 'object') ? Object.assign({}, v) : v;
newArray.push(val);
});
https://jsfiddle.net/e5hmnjp0/
https://jsfiddle.net/e5hmnjp0/
cheers
干杯
回答by DonCallisto
In JS, operator "=" copy the pointer to the memory area of the array. If you want to copy an array into another you have to use the Clone function.
在JS中,操作符“=”将指针复制到数组的内存区域。如果要将一个数组复制到另一个数组中,则必须使用 Clone 函数。
For integers is different because they are a primitive type.
对于整数是不同的,因为它们是原始类型。
S.
S。
回答by SLaks
You don't have any copies.
You have multiple variables holding the same array.
你没有任何副本。
您有多个变量保存相同的数组。
Similarly, you have multiple variables holding the same number.
同样,您有多个变量保存相同的数字。
When you write copyOfMyNumber = ...
, you're putting a new number into the variable.
That's like writing copyOfMyArray = ...
.
当您编写 时copyOfMyNumber = ...
,您将一个新数字放入变量中。
这就像写作copyOfMyArray = ...
。
When you write copyOfMyArray.splice
, you're modifying the original array.
That isn't possible with numbers because numbers are immutable and cannot be modified,
当您编写时copyOfMyArray.splice
,您正在修改原始数组。
这对数字来说是不可能的,因为数字是不可变的,不能修改,
回答by Quentin
Everything is copied by reference except primitive data types (strings and numbers IIRC).
除了原始数据类型(字符串和数字 IIRC)之外,所有内容都是通过引用复制的。
回答by Stack
Create a filter of the original array in the arrayCopy. So that changes to the new array won't affect original array.
在arrayCopy 中创建原始数组的过滤器。这样对新数组的更改不会影响原始数组。
var myArray = ['a', 'b', 'c'];
var arrayCopy = myArray.filter(function(f){return f;})
arrayCopy.splice(0, 1);
alert(myArray); // alerts ['a','b','c']
alert(arrayCopy); // alerts ['b','c']
Hope it helps.
希望能帮助到你。
回答by Omprakash Sharma
The issue with shallow copy is that all the objects aren't cloned, instead it get reference.So array.slice(0) will work fine only with literal array, but it will not do shallow copy with object array. In that case one way is..
浅拷贝的问题是所有的对象都没有被克隆,而是得到引用。所以 array.slice(0) 只适用于文字数组,但它不会对对象数组进行浅拷贝。在这种情况下,一种方法是..
var firstArray = [{name: 'foo', id: 121}, {name: 'zoo', id: 321}];
var clonedArray = firstArray.map((_arrayElement) => Object.assign({}, _arrayElement));
console.log(clonedArray);
// [{name: 'foo', id: 121}, {name: 'zoo', id: 321}] // shallow copy
回答by Erjim
You can add some error handling depending on your cases and use something similar to the following function to solve the issue. Please comment for any bugs / issues / efficiency ideas.
您可以根据您的情况添加一些错误处理,并使用类似于以下功能的东西来解决问题。请评论任何错误/问题/效率想法。
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;
}