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

В одной из своих предыдущих статей я рассказывал, как можно копировать объекты в JavaScript [/ how-to-copy-objects-in-javascript /]. Копирование объекта - довольно сложное занятие, учитывая, что вам также потребуется иметь возможность копировать любой другой тип данных, который может быть в объекте. Но что, если вы просто копируете массив? Как и в предыдущей статье, есть несколько способов выполнить эту задачу, некоторые из которых я рассмотрю в этой статье. Но сначала замечание о скорости. Хотя это может иметь значение не для всех приложений

В одной из моих предыдущих статей я рассказывал, как можно копировать объекты в 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. Мы также рассмотрели проблему глубокого клонирования массивов и какие решения существуют для ее решения.

Есть ли другой метод, который лучше всего подходит для вас? Дайте нам знать, что вы думаете, в комментариях.

comments powered by Disqus