为什么在 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 22:28:35  来源:igfitidea点击:

Why does changing an Array in JavaScript affect copies of the array?

javascript

提问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 myArrayand sets it to an array value. It then declares a second variable copyOfMyArrayand sets it to myArray. It performs an operation on copyOfMyArrayand then alerts both myArrayand 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 myNumberand sets it to a number value. It then declares a second variable copyOfMyNumberand sets it to myNumber. It performs an operation on copyOfMyNumberand then alerts both myNumberand copyOfMyNumber. Here, I get the expected behavior: different values for myNumberand copyOfMyNumber.

然后代码对数字值做同样的事情:它声明一个变量myNumber并将它设置为一个数字值。然后它声明了第二个变量copyOfMyNumber并将其设置为myNumber. 它对 和 执行操作copyOfMyNumber,然后向myNumber和发出警报copyOfMyNumber。在这里,我得到预期的行为:对不同的价值观myNumbercopyOfMyNumber

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 copyOfMyArrayit will not change myArrayeither.

顺便说一句,您与数字示例的比较不正确。您为 分配了一个新值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.

这是使用...传播语法。

Spread Syntax Source

扩展语法源

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.

我会推荐这篇文章,什么是不可变和可变数据结构?, 深入研究该主题。

MDN Glossary: Mutable

MDN 术语表:可变的

回答by Bosworth99

Cloning objects -

克隆对象 -

A loop / array.pushproduces 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;
}