Javascript передает массивы в функции по значению, оставляя исходный массив неизменным
Я прочитал много ответов здесь, касающихся "по значению" и "по ссылке" для передачи массивов в функции 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 массиву, и исходный массив все еще модифицируется.
Я также присоединил подэлементы к строке, обработал их, разделил их на массивы, и исходный массив все еще модифицировался.
Пожалуйста, кто-нибудь знает, как я могу передать значения массива функции и не изменить переданный массив?
Ответы
Ответ 1
Внутри вашей функции есть:
funcArray = new Array();
funcArray = someArray;
На самом деле это не копирует someArray
, а ссылается на него, поэтому исходный массив модифицируется.
Вы можете использовать Array.slice()
для создания так называемой мелкой копии массива.
var funcArray = someArray.slice(0);
Исходный массив будет не изменен, , но каждый из его элементов будет ссылаться на свои соответствующие записи в исходном массиве. Для "глубокого клонирования" вам нужно сделать это рекурсивно; наиболее эффективный способ обсуждается в следующем вопросе:
Каков наиболее эффективный способ глубокого клонирования объекта в JavaScript?
Btw, я добавил var
до funcArray
. Это делает его локальным для функции вместо глобальной переменной.
Ответ 2
Сделайте копию массива, который вы можете использовать.
Простым способом сделать это можно с помощью var clone = original.slice(0);
Ответ 3
Переменная, указывающая на массив, является ссылкой на нее. Когда вы передаете массив, вы копируете эту ссылку.
Вы можете сделать мелкую копию с slice()
. Если вы хотите получить полную копию глубины, то рекурсия в под-объектах, имея в виду оговорки при копировании некоторых объектов.
Ответ 4
Общее решение будет...
// 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
Если вам нужно сделать это с помощью объекта, попробуйте этот модный трюк...
MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT));
Ответ 6
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