Как клонировать массив в JavaScript

В JavaScript есть много способов сделать что-нибудь. Я написал о 10 способах написания конвейера / компоновки на JavaScript, а теперь мы делаем массивы.

1. Оператор распространения (мелкая копия)

С тех пор, как ES6 упал, это был самый популярный метод. Это краткий синтаксис, и вы найдете его невероятно полезным при использовании таких библиотек, как React и Redux.

numbers = [1, 2, 3]; numbersCopy = [...numbers]; 

Примечание. Это небезопасное копирование многомерных массивов. Значения массива / объекта копируются по ссылке, а не по значению .

Это отлично

numbersCopy.push(4); console.log(numbers, numbersCopy); // [1, 2, 3] and [1, 2, 3, 4] // numbers is left alone 

Это не нормально

nestedNumbers = [[1], [2]]; numbersCopy = [...nestedNumbers]; numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1, 300], [2]] // [[1, 300], [2]] // They've both been changed because they share references 

2. Старый добрый цикл for () (неглубокая копия)

Думаю, этот подход наименее популярен, учитывая, насколько модным стало функциональное программирование в наших кругах.

Чистый или нечистый, декларативный или императивный, он выполняет свою работу!

numbers = [1, 2, 3]; numbersCopy = []; for (i = 0; i < numbers.length; i++) { numbersCopy[i] = numbers[i]; } 

Примечание. Это небезопасное копирование многомерных массивов. Поскольку вы используете =оператор, он будет назначать объекты / массивы по ссылке, а не по значению .

Это отлично

numbersCopy.push(4); console.log(numbers, numbersCopy); // [1, 2, 3] and [1, 2, 3, 4] // numbers is left alone 

Это не нормально

nestedNumbers = [[1], [2]]; numbersCopy = []; for (i = 0; i < nestedNumbers.length; i++) { numbersCopy[i] = nestedNumbers[i]; } numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1, 300], [2]] // [[1, 300], [2]] // They've both been changed because they share references 

3. Старый добрый цикл while () (мелкая копия)

То же, что - forнечистое, императивное, бла, бла, бла… это работает! ?

numbers = [1, 2, 3]; numbersCopy = []; i = -1; while (++i < numbers.length) { numbersCopy[i] = numbers[i]; } 

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

Это отлично

numbersCopy.push(4); console.log(numbers, numbersCopy); // [1, 2, 3] and [1, 2, 3, 4] // numbers is left alone 

Это не нормально

nestedNumbers = [[1], [2]]; numbersCopy = []; i = -1; while (++i < nestedNumbers.length) { numbersCopy[i] = nestedNumbers[i]; } numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1, 300], [2]] // [[1, 300], [2]] // They've both been changed because they share references 

4. Array.map (неглубокая копия)

Вернувшись на современную территорию, мы найдем mapфункцию. Уходит корнями в математику, mapконцепция преобразования множества в другой тип множества, сохраняя структуру.

На английском это означает, что Array.mapкаждый раз возвращает массив одинаковой длины.

Чтобы удвоить список чисел, используйте mapс doubleфункцией.

numbers = [1, 2, 3]; double = (x) => x * 2; numbers.map(double); 

А как насчет клонирования ??

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

numbers = [1, 2, 3]; numbersCopy = numbers.map((x) => x); 

Если вы хотите быть более математическим, (x) => xэто называется идентичностью . Он возвращает любой заданный параметр.

map(identity) клонирует список.

identity = (x) => x; numbers.map(identity); // [1, 2, 3] 

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

5. Array.filter (мелкая копия)

Эта функция возвращает массив точно так же map, но не гарантированно имеет одинаковую длину.

Что, если вы фильтруете четные числа?

[1, 2, 3].filter((x) => x % 2 === 0); // [2] 

Длина входного массива равнялась 3, но результирующая длина - 1.

Однако если ваш filterпредикат всегда возвращается true, вы получаете дубликат!

numbers = [1, 2, 3]; numbersCopy = numbers.filter(() => true); 

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

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

6. Array.reduce (мелкая копия)

Мне почти плохо, когда я reduceклонирую массив, потому что он намного мощнее этого. Но поехали ...

numbers = [1, 2, 3]; numbersCopy = numbers.reduce((newArray, element) => { newArray.push(element); return newArray; }, []); 

reduce преобразует начальное значение при просмотре списка.

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

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

7. Array.slice (неглубокая копия)

sliceвозвращает мелкую копию массива на основе предоставленного вами начального / конечного индекса.

Если нам нужны первые 3 элемента:

[1, 2, 3, 4, 5].slice(0, 3); // [1, 2, 3] // Starts at index 0, stops at index 3 

If we want all the elements, don’t give any parameters

numbers = [1, 2, 3, 4, 5]; numbersCopy = numbers.slice(); // [1, 2, 3, 4, 5] 

Note: This is a shallow copy, so it also assigns objects/arrays by reference instead of by value.

8. JSON.parse and JSON.stringify (Deep copy)

JSON.stringify turns an object into a string.

JSON.parse turns a string into an object.

Combining them can turn an object into a string, and then reverse the process to create a brand new data structure.

Note: This onesafely copies deeply nested objects/arrays!

nestedNumbers = [[1], [2]]; numbersCopy = JSON.parse(JSON.stringify(nestedNumbers)); numbersCopy[0].push(300); console.log(nestedNumbers, numbersCopy); // [[1], [2]] // [[1, 300], [2]] // These two arrays are completely separate! 

9. Array.concat (Shallow copy)

concat combines arrays with values or other arrays.

[1, 2, 3].concat(4); // [1, 2, 3, 4] [1, 2, 3].concat([4, 5]); // [1, 2, 3, 4, 5] 

If you give nothing or an empty array, a shallow copy’s returned.

[1, 2, 3].concat(); // [1, 2, 3] [1, 2, 3].concat([]); // [1, 2, 3] 

Note: This also assigns objects/arrays by reference instead of by value.

10. Array.from (Shallow copy)

This can turn any iterable object into an array. Giving an array returns a shallow copy.

numbers = [1, 2, 3]; numbersCopy = Array.from(numbers); // [1, 2, 3] 

Note: This also assigns objects/arrays by reference instead of by value.

Conclusion

Well, this was fun ?

I tried to clone using just 1 step. You’ll find many more ways if you employ multiple methods and techniques.