Скопировать массив по значению - PullRequest
1575 голосов
/ 20 сентября 2011

При копировании массива в JavaScript в другой массив:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

Я понял, что arr2 относится к тому же массиву, что и arr1, а не к новому независимому массиву. Как я могу скопировать массив, чтобы получить два независимых массива?

Ответы [ 33 ]

11 голосов
/ 03 июля 2015

Если вы находитесь в среде ECMAScript 6 , используя оператор Spread , вы можете сделать это следующим образом:

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>
9 голосов
/ 15 апреля 2014

Добавляя к решению array.slice (); , помните, что если у вас есть многомерный массив, то вложенные массивы будут скопированы по ссылкам.Что вы можете сделать, это зациклить и нарезать () каждый под-массив по отдельности

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

То же самое относится к массиву объектов, они будут скопированы по ссылке, вы должны скопировать их вручную

6 голосов
/ 26 марта 2017

Как мы знаем в Javascript массивы и объекты являются ссылками, но как мы можем сделать копию массива, не изменяя исходный массив позже, чем один?

Вот несколько способов сделать это:

Представьте, что у вас есть этот массив в вашем коде:

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

1) Циклически перебирая массив в функции и возвращаяновый массив, например:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) Используя метод слайса, слайс предназначен для нарезки части массива, он будет нарезать некоторую часть массива, не касаясь оригинала, в слайсе, если неt указывает начало и конец массива, он нарезает весь массив и в основном делает полную копию массива, поэтому мы можем легко сказать:

var arr2 = arr.slice(); // make a copy of the original array

3) Также метод контакта, это дляобъединение двух массивов, но мы можем просто указать один из массивов, и тогда это в основном сделает копию значений в новом контактном массиве:

var arr2 = arr.concat();

4) Также метод stringify и parse, это не рекомендуется, номожет быть простым способом скопировать массив и объекты:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Метод Array.from, который широко не поддерживается, перед использованием проверьте поддержку в различных браузерах:

const arr2 = Array.from(arr);

6) способ ECMA6, также не полностью поддерживается,но babelJs может помочь вам, если вы хотите провести:

const arr2 = [...arr];
4 голосов
/ 13 мая 2014

В моем конкретном случае мне нужно было убедиться, что массив остался нетронутым, так что это сработало для меня:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}
4 голосов
/ 22 июля 2014

Сделать копию многомерного массива / объекта:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

Спасибо Джеймсу Падолси за эту функцию.

Источник: Здесь

3 голосов
/ 06 августа 2018

Когда мы хотим скопировать массив с помощью оператора присваивания (=), он не создает копию, а просто копирует указатель / ссылку на массив.Например:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

Часто, когда мы преобразуем данные, мы хотим сохранить исходную структуру данных (например, массив) нетронутой.Мы делаем это путем создания точной копии нашего массива, чтобы его можно было преобразовать, оставив исходный без изменений.

Способы копирования массива:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

Будьте осторожны при вложении массивов или объектов!:

При вложении массивов значения копируются по ссылке.Вот пример того, как это может привести к проблемам:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

Поэтому не используйте эти методы, когда в вашем массиве есть объекты или массивы, которые вы хотите скопировать.т.е. использовать эти методы только для массивов примитивов.

Если вы хотите глубоко клонировать массив javascript, используйте JSON.parse в сочетании с JSON.stringify, например:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

Производительность копирования:

Итак, какой из них мы выбираем для оптимальной производительности.Оказывается, что самый многословный метод, цикл for имеет самую высокую производительность.Используйте цикл for для действительно интенсивного копирования процессора (большой / много массивов).

После этого метод .slice() также имеет приличную производительность, а также менее многословен и прост для реализации программистом.Я предлагаю использовать .slice() для ежедневного копирования массивов, которые не сильно нагружают процессор.Также избегайте использования JSON.parse(JSON.stringify(arr)) (много накладных расходов), если глубокое клонирование не требуется и производительность является проблемой.

Тест производительности источника

3 голосов
/ 26 сентября 2018

Если ваш массив содержит элементы примитивного типа данных , такие как int, char или string и т. Д. , то вы можете использовать один из тех методов, который возвращает копию исходного массиватакие как .slice () или .map () или оператор распространения (благодаря ES6).

new_array = old_array.slice()

или

new_array = old_array.map((elem) => elem)

или

const new_array = new Array(...old_array);

НО , если ваш массив содержит сложных элементов , таких как объекты (или массивы) или более вложенных объектов , то вам необходимо убедиться, что вы делаете копиюиз всех элементов от верхнего уровня до последнего уровня, в противном случае будет использоваться ссылка на внутренние объекты, и это означает, что изменение значений в object_elements в new_array все равно повлияет на old_array.Вы можете вызвать этот метод копирования на каждом уровне как создание DEEP COPY для old_array.

Для глубокого копирования вы можете использовать вышеупомянутые методы для примитивных типов данных на каждом уровнев зависимости от типа данных или вы можете использовать этот дорогостоящий метод (упомянутый ниже) для создания глубокой копии без особой работы.

var new_array = JSON.parse(JSON.stringify(old_array));

Существует множество других методовТам вы можете использовать в зависимости от ваших требований.Я упомянул только некоторые из них, чтобы дать общее представление о том, что происходит, когда мы пытаемся скопировать массив в другой по значению .

3 голосов
/ 18 мая 2018

Дэн, не нужно использовать причудливые трюки.Все, что вам нужно сделать, это сделать копию arr1, выполнив это.

var arr2 = new Array(arr1);

Теперь arr1 и arr2 - это две разные переменные массива, которые хранятся в отдельных стеках. Проверьте это на jsfiddle .

2 голосов
/ 12 апреля 2018

Вот еще несколько способов копирования:

const array = [1,2,3,4];

const arrayCopy1 = Object.values(array);
const arrayCopy2 = Object.assign([], array);
const arrayCopy3 = array.map(i => i);
const arrayCopy4 = Array.of(...array );
2 голосов
/ 30 июня 2017

Вы также можете использовать оператор распространения ES6 для копирования массива

var arr=[2,3,4,5];
var copyArr=[...arr];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...