如何在不改变原始参数数组的情况下操作传递给函数的 JavaScript 数组?

3
我希望能够在不改变原始数组的情况下,与传递给函数的数组一起工作。以下是问题的简单示例。
function whyDoesArrChange(arr) {
   var newArr = arr;
   newArr.push(4);

   return arr;
 }
 
 console.log(whyDoesArrChange([1,2,3]));
// OUT: [1,2,3,4]

我只希望更改newArr,但是参数中的arr也会返回推送的值(返回[1,2,3,4])。我该如何避免这种情况?


答案将取决于数组中的元素是否需要保持不变。正如Marcos Casagrande已经建议的那样,您可以使用slice生成原始数组的子集。这样做将通过引用复制该数组中的任何对象。 - Jon Trauntvein
4个回答

7

当将数组传递给函数时,该数组的值是一个引用,您必须克隆它以打破引用。

有多种方法可以实现这一点:

1 - 使用 .slice();

var newArr = arr.slice();

2 - 使用 .concat 方法

var newArr = arr.concat([]);

3 - Using JSON.parse & JSON.stringify

var newArr = JSON.parse(JSON.stringify(arr));

你可以查看这个我找到的jsperf,以了解更多的方法并查看它们的表现。

有人可以解释一下为什么改变newArr也会改变arr吗?为什么.slice()这么特殊,它不会改变arr?谢谢,我在这里学到了很多。 - user1486510
为什么 .slice() 如此特殊,以至于它不会改变 arr?谢谢,我在这里学到了很多。slice 创建一个新的数组,因此它不会改变 arr。 - Marcos Casagrande
关于你的第一个问题,请查看这个链接:https://medium.com/@naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600,因为在这里解释有点宽泛。 - Marcos Casagrande
1
感谢您的回答,非常有帮助。 - user1486510

1
在JavaScript中,当你使用(=)将一个变量的值赋给另一个变量时,你只是传递了整个变量,所以每次一个变量或另一个变量的值改变时,另一个变量也会改变。
根据你的问题,我觉得最好的方法是对数组对象使用本地的.slice() JavaScript方法。对于你的代码:
function whyDoesArrChange(arr) {
    var newArr = arr.slice();
    newArr.push(4);
    return arr;
}

在JavaScript中,当您使用(=)将一个变量的值分配给另一个变量时,您只是传递整个变量,因此每次其中一个变量更改时,另一个变量也会更改。但这并不总是正确的,例如x = 4; y = x; y = 5;将不会更改x的值。这是因为x被赋予了一个原始值。对于非原始值(如对象或数组),赋值是通过引用进行的,其中每个变量链接到内存中相同的数据,因此更改一个变量将更改另一个变量。 - Gershon Papi
非常感谢您的见解,我非常感激。 - user1486510

1
虽然马科斯的答案是正确的,毫无疑问。还有更多纯粹的数组函数可以使用(纯函数是指不改变其范围之外的数据的函数)。
通常,如果您想对数组执行多个操作,我会选择马科斯的答案,然后像往常一样进行这些更改。但当情况不是这样时,以下信息可能会有用:
  1. 添加:arr.concat([1]);
  2. 子数组(i到j):arr.slice(i, j + 1);
  3. 删除(i到j):arr.slice(0, i).concat(arr.slice(j + 1));
此外,filtermap是不会改变数组的纯函数。

0

因为引用类型(数组和对象)作为参数传递给函数时可以在函数内部被修改,而原始类型(数字、字符串、布尔值等)则不会。

您可以使用 .slice() 方法创建一个浅拷贝的数组,并对该数组进行操作,或者使用 .concat 方法返回一个新的数组。

function whyDoesArrChange(arr) {
   return arr.concat(4);
 }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接