Когда мы хотим скопировать массив с помощью оператора присваивания (=
), он не создает копию, а просто копирует указатель / ссылку на массив.Например:
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))
(много накладных расходов), если глубокое клонирование не требуется и производительность является проблемой.
Тест производительности источника