我在这里读到了很多关于“按值”和“按引用”传递以将数组发送到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数组,原始数组仍然会被修改。
我还将子元素连接到一个字符串,处理它们,将它们拆分成数组,原始数组仍然被修改。
请问,有没有人知道如何将数组值传递给函数而不传递数组?
答案 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 syntax和destructuring直接在参数列表中执行浅表复制,从而使原始数组保持不变。
请参见以下示例:
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