Я прочитал здесь много ответов, касающихся «по значению» и «по ссылке», передаваемых для отправки массивов в функции 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-му массиву, а исходный массив все еще изменяется.

Я также соединил подэлементы в строку, обработал их, разделил их на массивы, и исходный массив все еще изменяется.

Пожалуйста, кто-нибудь знает, как я могу передать значения массива в функцию и не изменить переданный массив?

39
Dave Pritlove 24 Янв 2013 в 03:36

9 ответов

Лучший ответ

Внутри вашей функции есть это:

funcArray = new Array();
funcArray = someArray;

На самом деле это не будет копировать someArray, а вместо этого ссылаться на него, поэтому исходный массив модифицируется.

Вы можете использовать Array.slice(), чтобы создать так называемую мелкую копию массива.

var funcArray = someArray.slice(0);

Исходный массив будет неизменным, но каждый из его элементов будет по-прежнему ссылаться на соответствующие им записи в исходном массиве. Для «глубокого клонирования» вам нужно сделать это рекурсивно; Наиболее эффективный способ обсуждается в следующем вопросе:

Каков наиболее эффективный способ глубокого клонирования объекта в JavaScript?

Кстати, я добавил var раньше funcArray. Это делает его локальным для функции, а не глобальной переменной.

43
Community 23 Май 2017 в 11:54

В ES6 вы можете использовать синтаксис распространения и деструктуризация для выполнения мелкой копии непосредственно в списке аргументов, что позволяет сохранить исходный массив без изменений.

См. Пример ниже:

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
0
Nick Parsons 28 Дек 2019 в 02:13

Общее решение будет ...

// 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 типы данных

  • Невозможно клонировать циклические ссылки

0
Split Your Infinity 27 Дек 2013 в 23:29

Если вам нужно сделать это с объектом, попробуйте этот причудливый трюк ...

MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT));
0
doublejosh 20 Фев 2014 в 01:24
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
-1
Elisha McNutt 25 Сен 2017 в 23:38

Как насчет назначения для деструктуры (ES6 +, проверьте совместимость)? Хорошее и чистое решение.

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});
1
Bardr 27 Фев 2019 в 19:42

Сделайте копию массива, который вы можете использовать.

Простой способ сделать это с помощью var clone = original.slice(0);

8
Tyler Hughes 23 Янв 2013 в 23:42

По умолчанию в javascript, кроме объектов и массивов, все копируется по значению, но если вы хотите использовать копирование по значению для массивов: используйте [yourArray] .slice (0), а для объектов используйте Object.assign (target,. ..sources )

0
Sandeep Gantait 23 Дек 2019 в 09:30

Переменная, указывающая на массив, является ссылкой на него. Когда вы передаете массив, вы копируете эту ссылку.

Вы можете сделать поверхностную копию с помощью slice() . Если вы хотите получить копию с полной глубиной, используйте субобъекты с учетом предостережений при копировании некоторых объектов.

1
alex 23 Янв 2013 в 23:41