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

IT技术 javascript
2021-01-14 03:41:08

我编写了以下 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        

此代码声明一个变量myArray并将其设置为数组值。然后它声明了第二个变量copyOfMyArray并将其设置为myArray. 它对 和 执行操作copyOfMyArray,然后向myArray发出警报copyOfMyArray不知何故,当我对 执行操作时copyOfMyArray,似乎对 执行了相同的操作myArray

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

JavaScript 中的数组和数字之间有什么区别,似乎更改数组会更改数组副本的值,而更改数字不会更改数字副本的值?

我猜出于某种原因,数组是通过引用引用的,而数字是通过值引用的,但为什么呢?我如何知道其他对象的预期行为?

6个回答

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

顺便说一句,您与数字示例的比较不正确。您为 分配了一个新值copyOfMyNumber如果您为其分配一个新值,copyOfMyArray它也不会改变myArray

您可以使用slice [docs]创建数组的副本

var copyOfMyArray = myArray.slice(0);

但请注意,这仅返回拷贝,即不会克隆数组内的对象。

@jAndy:啊,所以你提到了那个......我只是有点困惑,最近我更经常用另一种方式;)
2021-03-15 03:41:08
@Rice:不,我只是编辑以澄清。如果你想要一个深拷贝,你必须自己写一些东西。但我相信你会找到一个脚本来做到这一点。
2021-03-29 03:41:08
@FelixKling:我没有例子。我只是问,因为您首先应用了原型方法。
2021-04-02 03:41:08
+1 - 只是出于好奇,myArray.slice(0);在这种情况下直接分配有什么缺点吗?
2021-04-06 03:41:08

好吧,唯一可能的答案——也是正确的答案——是你实际上并没有复制数组。当你写

var copyOfArray = array;

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

我想说的是,您并没有准确地分配引用指针,而是像引用的副本一样进行分配。因为如果您将 obj 传递给函数并尝试用函数内的另一个新对象替换它,那么您将不会更改原始对象。
2021-04-02 03:41:08
@kashesandr 是的,“分配引用”意味着“分配引用副本”,这是真的。然而,两个相等的引用总是相等的,就像数字的两个实例5总是相等的一样。
2021-04-02 03:41:08

所以这里的每个人都很好地解释了为什么会发生这种情况——我只是想留下一条线,让你知道我是如何解决这个问题的——很容易:

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

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

扩展语法源

编辑:至于为什么会这样,并回答您的问题:

JavaScript 中的数组和数字之间有什么区别,似乎更改数组会更改数组副本的值,而更改数字不会更改数字副本的值?

答案是在 JavaScript 中,数组和对象是可变的,而字符串和数字以及其他原语是不可变的当我们做这样的任务时:

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;

copyOfMyArray 实际上只是对 myArray 的引用,而不是实际的副本。

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

MDN 术语表:可变的

正是我要找的。
2021-03-30 03:41:08

克隆对象 -

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

以下面的例子为例:

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 索引上运行的操作都会产生所需的结果,除了最终(对象),因为它是通过引用复制的,所以也会改变 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/

干杯

在JS中,操作符“=”将指针复制到数组的内存区域。如果要将一个数组复制到另一个数组中,则必须使用 Clone 函数。

For integers 是不同的,因为它们是原始类型。

S。