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

时间:2013-01-23 23:36:56

标签: 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 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;

}

我无法理解为什么这个函数中的任何东西都应该改变原始数组。

如果将函数调用分配给新数组,则

直接调用此函数会更改原始数组:

myArray = [["A","B","C"],["D","E","F"],["G","H","I"]];
anotherArray = new Array();

anotherArray = myFunction(myArray);
// myArray gets modified!;

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

anotherArray = myFunction(myArray.valueOf());
// myArray gets modified!;

我甚至尝试按子元素按元素和子元素分解数组,并将所有数据分配给新的2-d数组,原始数组仍然会被修改。

我还将子元素连接到一个字符串,处理它们,将它们拆分成数组,原始数组仍然被修改。

请问,有没有人知道如何将数组值传递给函数而不传递数组?

9 个答案:

答案 0 :(得分:38)

在你的功能中有这样的:

funcArray = new Array();
funcArray = someArray;

这实际上不会复制someArray,而是引用它,这就是修改原始数组的原因。

您可以使用Array.slice()创建所谓的数组浅表副本。

var funcArray = someArray.slice(0);

原始数组将不会改变,其每个元素仍将引用原始数组中的相应条目。对于“深度克隆”,你需要递归地执行此操作;以下问题讨论了最有效的方法:

What is the most efficient way to deep clone an object in JavaScript?

顺便说一下,我在var之前添加了funcArray。这样做使其成为函数的本地函数而不是全局变量。

答案 1 :(得分:7)

制作可以使用的数组的副本。

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

答案 2 :(得分:1)

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

您可以使用slice()制作浅色副本。如果你想要一个完整的深度复制,那么递归子对象,记住复制一些对象时的注意事项。

答案 3 :(得分:1)

destructuring assignment(ES6 +,检查compatibility)如何?干净的解决方案。

function myFunction(someArray) {

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

let myArray = [["A","B","C"],["D","E","F"],["G","H","I"]];

// Using destructuring assignment.
// NOTE: We can't just use `[...myArray]` because nested arrays will still be copied by reference.
let anotherArray = myFunction([...myArray.map(nested => [...nested])]);

console.log({original: myArray, copy: anotherArray});

答案 4 :(得分:0)

通用的解决方案是......

// 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支持的数据类型的函数

  • 无法克隆循环引用

答案 5 :(得分:0)

如果你需要用一个物体做这个,试试这个花哨的技巧......

MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT));

答案 6 :(得分:0)

在javascript中,默认情况下,对象和数组除外,所有内容均按值复制 但是,如果要对数组使用按值复制:请使用[yourArray] .slice(0) 对于对象,请使用Object.assign(target,... sources)

答案 7 :(得分:0)

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

请参见以下示例:

const arr = [1, 2, 3, 4, 5];

function timesTen([...arr]) { // [...arr] shallow copy the array
  for(let i = 0; i < arr.length; i++) {
    arr[i] *= 10; // this would usually change the reference
  }
  return arr;
}

console.log(timesTen(arr));
console.log(arr); // unaltered

答案 8 :(得分:-1)

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]);

此答案已经过编辑。最初我提出new运算符处理了解决方案,但很快就发现了错误。相反,我选择使用concat()方法来创建副本。原始答案没有显示整个阵列,因此错误被无意中隐藏了。下面显示的新输出将证明此答案按预期工作。

aArray: 0, 1, 2
aArrayCopy: A changed value., 1, 2