В одной из моих предыдущих статей я рассказывал, как можно копировать объекты в JavaScript . Копирование объекта - довольно сложное занятие, учитывая, что вам также потребуется иметь возможность копировать любой другой тип данных, который может быть в объекте. Но что, если вы просто копируете массив? Как и в предыдущей статье, есть несколько способов выполнить эту задачу, некоторые из которых я рассмотрю в этой статье.
Но сначала замечание о скорости. Хотя это может иметь значение не для всех приложений, следует учитывать, является ли копирование больших массивов обычной операцией в вашем коде или скорость действительно имеет значение. Для некоторых из приведенных ниже методов я отмечаю их скорость по сравнению с другими методами, которая исходит из результатов этого теста .
Копирование простых массивов
Для этой первой части предположим, что массив, который вы хотите скопировать, содержит только примитивные (и неизменяемые) типы данных. То есть массив содержит только числа, логические значения, строки и т. Д. Таким образом, мы можем больше сосредоточиться на передаче данных из одного массива в другой, а не на том, как мы обрабатываем копирование фактического содержимого массива, что я обложку в разделе «Глубокие копии» ниже.
Существует удивительное количество способов скопировать массив, некоторые из которых включают:
push
- Распространение
slice
Array.from
_.clone
Оператор распространения и slice
- самые быстрые способы скопировать
неглубокий массив, но имейте в виду, что это зависит от базовой среды
выполнения, поэтому это может быть не универсально верно.
Толкать
Это, вероятно, наиболее очевидное решение, которое перебирает исходный
массив и использует push()
нового массива для добавления элементов из
одного массива в другой:
let oldArr = [3, 1, 5, 2, 9];
let newArr = [];
for (let i=0; i < oldArr.length; i++) {
newArr.push(oldArr[i]);
}
Мы просто перебираем копируемый массив и помещаем каждый элемент в новый массив.
Распространение
В этом методе используется оператор распространения , который был определен в ES6 и доступен в большинстве современных браузеров.
Это работает следующим образом:
let oldArr = [3, 1, 5, 2, 9];
let newArr = [...oldArr];
Если я собираюсь использовать собственное решение, а не стороннюю библиотеку, то это обычно решение, которое я предпочитаю благодаря его чистому и простому синтаксису.
Одно важное замечание: это копирование работает только на верхнем уровне (как и многие из этих методов), поэтому его не следует использовать, если вам нужны глубокие копии чего-либо.
Ломтик
Метод slice()
обычно используется для возврата части массива, заданной
параметрами beginning
и end
. Однако, если параметры не переданы,
возвращается копия всего массива:
let oldArr = [3, 1, 5, 2, 9];
let newArr = oldArr.slice();
Во многих средах выполнения JavaScript это самый быстрый способ скопировать массив.
Array.from
Метод Array.from
предназначен для создания неглубокой копии любой
итерации, которую вы ему передаете, а также принимает дополнительную
функцию сопоставления в качестве второго параметра. Таким образом, его
можно использовать для создания массива из строк, наборов, карт и,
конечно же, других массивов:
let oldArr = [3, 1, 5, 2, 9];
let newArr = Array.from(oldArr);
Клон Лодаша
Методы clone () и cloneDeep () в Lodash могут быть вам знакомы, если вы прочитаете эту статью о копировании объектов. Методы делают именно то, что вы ожидаете - любой переданный ему объект (или массив, примитив и т. Д.) Будет скопирован и возвращен.
_.cloneDeep
(описанный ниже) отличается тем, что он не прекращает
клонирование на верхнем уровне, он рекурсивно копирует все объекты, с
которыми сталкивается на любом уровне.
Учитывая это, мы можем использовать его также для копирования массивов:
let oldArr = [3, 1, 5, 2, 9];
let newArr = _.clone(oldArr);
_.clone
работает очень хорошо по сравнению с другими методами,
поэтому, если вы уже используете эту библиотеку в своем приложении, это
простое решение.
Глубокие копии
Следует отметить одну важную вещь: все методы, описанные выше, выполняют только поверхностные копии ваших массивов. Поэтому, если у вас есть массив объектов, например, фактический массив будет скопирован, но базовые объекты будут переданы по ссылке в новый массив.
Чтобы продемонстрировать эту проблему, давайте рассмотрим пример:
let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let newArr = [...oldArr];
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
false
true
Здесь вы можете видеть, что, хотя фактический массив является новым, объекты в нем не были. Для некоторых приложений это может быть большой проблемой. Если это относится к вам, попробуйте еще несколько способов.
Лодаш Клон Глубокий
Метод _.cloneDeep _.cloneDeep
делает то же самое, что и _.clone()
,
за исключением того, что он рекурсивно клонирует все в массиве (или
объекте), который вы ему передаете. Используя тот же пример, что и выше,
мы видим, что использование _.cloneDeep()
предоставит нам как новый
массив, так и скопированные элементы массива:
const _ = require('lodash');
let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let newArr = _.cloneDeep(oldArr);
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
false
false
Методы JSON
JavaScript действительно предоставляет несколько удобных методов JSON, которые обрабатывают преобразование большинства типов данных JS в строку, а затем действительную строку JSON в объект JS. Соответствующие методы используются следующим образом:
let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let arrStr = JSON.stringify(oldArr);
console.log(arrStr);
let newArr = JSON.parse(arrStr);
console.log(newArr);
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
'[{"foo":"bar"},{"baz":"qux"}]'
[ { foo: 'bar' }, { baz: 'qux' } ]
false
false
Этот метод отлично работает и не требует сторонних библиотек. Однако есть две основные проблемы:
- Данные должны быть сериализуемыми и десериализуемыми через JSON.
- Использование методов JSON таким образом намного медленнее, чем другие решения.
Поэтому, если у вас есть данные, которые нельзя сериализовать в JSON, или если скорость важна для вашего приложения, это может быть не лучшим решением для вас.
Заключение
В этой статье я рассмотрел несколько способов копирования массивов в JavaScript, используя как собственный код, так и полезную стороннюю библиотеку в Lodash. Мы также рассмотрели проблему глубокого клонирования массивов и какие решения существуют для ее решения.
Есть ли другой метод, который лучше всего подходит для вас? Дайте нам знать, что вы думаете, в комментариях.