Javascript通过值将数组传递给函数,保持原始数组不变

Javascript通过值将数组传递给函数,保持原始数组不变,javascript,arrays,Javascript,Arrays,我在这里读到了许多关于“按值”和“按引用”传递的答案,它们用于向javascript函数发送数组。但是,我在向函数发送数组并保持原始数组不变时遇到问题。此示例说明了问题: function myFunction(someArray) { // any function that makes an array based on a passed array; // someArray has two dimensions; // I've tried copying the passed arra

我在这里读到了许多关于“按值”和“按引用”传递的答案,它们用于向javascript函数发送数组。但是,我在向函数发送数组并保持原始数组不变时遇到问题。此示例说明了问题:

function myFunction(someArray)
{
// any function that makes an array based on a passed array;
// someArray has two dimensions;
// I've tried copying the passed array to a new array like this (I've also used 'someArray' directly in the code);

funcArray = new Array();
funcArray = someArray;

var i = 0;

    for(i=0; i<funcArray.length; i++)
    {
    funcArray[i].reverse;
    }

return funcArray;

}
我尝试使用.valueOf()发送原语:

anotherArray = myFunction(myArray.valueOf());
// myArray gets modified!;
我甚至尝试过将数组按元素和子元素逐个分解,并将所有元素分配给一个新的二维数组,而原始数组仍然会被修改

我还将子元素连接到一个字符串中,对它们进行处理,然后将它们拆分回数组,原始数组仍然会被修改


请问,有人知道我如何将数组值传递给函数而不改变传递的数组吗?

在您的函数中有以下内容:

funcArray = new Array();
funcArray = someArray;
这实际上不会复制someArray,而是引用它,这就是修改原始数组的原因

可以使用创建阵列的所谓浅拷贝

var funcArray = someArray.slice(0);
原始数组将保持不变,但其每个元素仍将引用原始数组中相应的条目。对于“深度克隆”,您需要递归地执行此操作;以下问题讨论了最有效的方法:


顺便说一句,我在
funcArray
之前添加了
var
。这样做会使它成为函数的局部变量,而不是全局变量。

指向数组的变量是对它的引用。当您传递数组时,您正在复制此引用


你可以用它做一个浅显的副本。如果需要完整的深度复制,则在子对象中递归,请记住复制某些对象时的注意事项。

通用解决方案是

// Use the JSON parse to clone the data.
function cloneData(data) {
  // Convert the data into a string first
  var jsonString = JSON.stringify(data);

  //  Parse the string to create a new instance of the data
  return JSON.parse(jsonString);
}

// An array with data
var original = [1, 2, 3, 4];

function mutate(data) {
  // This function changes a value in the array
  data[2] = 4;
}

// Mutate clone
mutate(cloneData(original));

// Mutate original
mutate(original);
这适用于对象和数组

在需要深度克隆或不知道类型时非常有效

深度克隆示例

var arrayWithObjects = [ { id: 1 }, { id: 2 }, { id: 3 } ];

function mutate(data) {
  // In this case a property of an object is changed!
  data[1].id = 4;
}

// Mutates a (DEEP) cloned version of the array
mutate(cloneData(arrayWithObjects));

console.log(arrayWithObjects[1].id) // ==> 2
警告

  • 使用JSON解析器进行克隆并不是最有效的选择

  • 它不克隆函数,只克隆JSON支持的数据类型

  • 无法克隆循环引用


制作一份可以使用的阵列副本


一种简单的方法是使用
var clone=original.slice(0)

如果需要对对象执行此操作,请尝试此奇特的技巧

MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT));
此答案已编辑。起初,我提出由
new
操作员处理解决方案,但很快就意识到了这个错误。相反,我选择使用concat()方法创建副本。原始答案没有显示整个阵列,因此错误被无意中隐藏了。下面显示的新输出将证明此答案按预期工作

aArray: 0, 1, 2
aArrayCopy: A changed value., 1, 2
那(ES6+,检查)呢?漂亮干净的解决方案

函数myFunction(someArray){
for(设i=0;i[…nested]));

log({original:myArray,copy:anotherArray})默认情况下,在javascript中,除了对象和数组之外,所有内容都是按值复制的 但如果要对数组使用“按值复制”:请使用[yourArray].slice(0) 对于对象,请使用Object.assign(target,…sources)

使用ES6,您可以使用和直接在参数列表中执行浅复制,从而使原始数组保持不变

见下例:

const arr=[1,2,3,4,5];
函数timesTen([…arr]){/[…arr]浅拷贝数组
for(设i=0;iconsole.log(arr);//原封不动
对不起,我忘了提到slice方法也没有什么区别。我见过上面提到的并尝试过,但它并没有阻止原始数组的更改(也没有阻止.valueOf()将数组内容简化为原语),我现在进一步探讨了slice()的概念,问题在于它是一个二维数组。如果我对外部数组进行切片,则没有任何区别,原始数组仍然会被更改。但是,如果我切片每个子数组,它就会工作!我为每个外部元素设置了一个循环,并将其切片分配给一个新数组的外部元素。根据我的第二条评论,slice()使其工作,但只有通过循环应用于二维数组的每个外部元素。这看起来很全面,但我不熟悉json。看来我应该投资去了解更多。现在,通过循环每个外部元素并将其.slice()分配给一个新数组,问题就解决了。在您的示例中,
cloneData
不应该只是
clone
(或者反过来)?@neemzy正确!更改了。谢谢,是的,我发现如果我依次切割每个外部元素,它现在就可以工作了。谢谢。我发现slice只在通过循环应用于每个外部元素时才起作用:newArray[I]=array[I]。slice()该代码不会按照您的想法执行,使用
newArray(aArray)
创建一个新数组,其中第一个元素是
aArray
,而不是复制原始数组,记录完整的数组而不是第一个元素,您将看到差异。谢谢Alberto。你反应很快,而且是正确的。使用
新数组(someArray)
会将长度设置为1,并将第一个元素设置为传递的arrray的引用,而不会像传递值所期望的那样为每个元素分配适当的值。我最近经常使用Float32Array,不得不重新认识到基本数组的构造方式不同。我的测试样本输出没有识别错误。现在它的结果是正确的
var aArray = [0.0, 1.0, 2.0];
var aArrayCopy = aArray.concat();
aArrayCopy[0] = "A changed value.";
console.log("aArray: "+aArray[0]+", "+aArray[1]+", "+aArray[2]);
console.log("aArrayCopy: "+aArrayCopy[0]+", "+aArrayCopy[1]+", "+aArrayCopy[2]);
aArray: 0, 1, 2
aArrayCopy: A changed value., 1, 2