Как скопировать массив в js
Перейти к содержимому

Как скопировать массив в js

Копирование массивов — Оператор spread

Копирование массивов в JavaScript — Существует несколько способов.

1-ый способ копирования массивов: написать функцию, используя циклы (см. пример здесь, так как массивы — это частный случай объектов).

2-ой способ копирования массивов — метод slice.

3-ий момент: если присвоить массив какой-либо переменной , то это НЕ будет являться копированием . В переменную будет передана ссылка на исходный массив, но не сам массив: подробнее об этом читайте здесь.

Оператор spread — Копирование массивов

Оператор разворота spread работает, начиная со стандарта JavaScript ES6 и используется для копирования массивов.

Синтаксис оператора spread — три точки .

Оператор spread — Примеры
Пример 1.1

Оператор spread — три точки.

1. Копирование массива letters в lettersNew .

2. Изменение значения одного из элементов массива lettersNew .

3. Исходный массив letters — остается прежним.

Пример 1.2

В результате в один массив были скопированы два других массива + есть возможность добавления дополнительных элементов .

Оператор spread — На практике

Оператор spread на практике часто используется для передачи массива в функцию .

Как это выглядит? Рассмотрим пример.

Допустим, мы получаем данные в виде массива. Например, ФИО, адрес и возраст. И есть функция с тремя параметрами, которая обрабатывает эти данные определенным образом. Рассмотрим эту ситуацию в простом исполнении. Здесь важно уловить суть .

Пример 2.1

Оператор spread раскладывает массив на отдельные элементы.

Оператор spread — Копирование объекта

В стандарте JavaScript ES8 оператор spread работает и для объектов .

Пример 3.1

Оператор spread — в результате копирования мы имеем два независимых объекта .

Оператор spread делает поверхностную — НЕ глубокую копию объекта/массива.

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

Как скопировать массив в js

Язык JavaScript предоставлет богатые возможности для работы с массивами, которые реализуются с помощью методов объекта Array. Рассмотрим применение этих методов

Копирование массива. slice()

Копирование массива может быть поверхностным или неглубоким (shallow copy) и глубоким (deep copy).

При неглубоком копировании достаточно присвоить переменной значение другой переменной, которая хранит массив:

В данном случае переменная people после копирования будет указывать на тот же массив, что и переменная users. Поэтому при изменении элементов в people, изменятся элементы и в users, так как фактически это один и тот же массив.

Такое поведение не всегда является желательным. Например, мы хотим, чтобы после копирования переменные указывали на отдельные массивы. И в этом случае можно использовать глубокое копирование с помощью метода slice() :

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

Но тут стоит отметить, что то же самое копирование по сути можно выполнить и с помощью spread-оператора . :

Также метод slice() позволяет скопировать часть массива. Для этого он принимает два параметра:

Первый параметр указывает на начальный индекс элемента, с которого которые используются для выборки значений из массива. А второй параметр — конечный индекс, по который надо выполнить копирование.

Например, выберем в новый массив элементы, начиная с 1 индекса по индекс 4 не включая:

И поскольку индексация массивов начинается с нуля, то в новом массиве окажутся второй, третий и четвертый элемент.

Если указан только начальный индекс, то копирование выполняется до конца массива:

Метод push() добавляет элемент в конец массива:

Метод pop() удаляет последний элемент из массива:

shift()

Метод shift() извлекает и удаляет первый элемент из массива:

unshift()

Метод unshift() добавляет новый элемент в начало массива:

Удаление элемента по индексу. splice()

Метод splice() удаляет элементы с определенного индекса. Например, удаление элементов с третьего индекса:

Метод splice возвращает удаленные элементы в виде нового массива.

В данном случае удаление идет с начала массива. Если передать отрицательный индекс, то удаление будет производиться с конца массива. Например, удалим последний элемент:

Дополнительная версия метода позволяет задать количество элементов для удаления. Например, удалим с первого индекса три элемента:

Еще одна версия метода splice позволяет вставить вместо удаляемых элементов новые элементы:

В данном случае удаляем три элемента с 1-го индекса и вместо них вставляем два элемента.

concat()

Метод concat() служит для объединения массивов. В качестве результата он возвращает объединенный массив:

Метод join() объединяет все элементы массива в одну строку, используя определенный разделитель, который передается через параметр:

В метод join() передается разделитель между элементами массива. В данном случае в качестве разделителя будет использоваться точка с запятой и пробел («; «).

Метод sort() сортирует массив по возрастанию:

Стоит отметить, что по умолчанию метод sort() рассматривает элементы массива как строки и сортирует их в алфавитном порядке. Что может привести к неожиданным результатам, например:

Здесь мы хотим отсортировать массив чисел, но результат может нас обескуражить: [15, 200, 35, 5] . В этом случае мы можем настроить метод, передав в него функцию сортировки. Логику функции сортировки мыы определяем сами:

Функция сортировки получает два рядом расположенных элемента массива. Она возвращает положительное число, если первый элемент должен находится перед вторым элементом. Если первый элемент должен располагаться после второго, то возвращается отрицательное число. Если элементы равны, возвращается 0.

reverse()

Метод reverse() переворачивает массив задом наперед:

Поиск индекса элемента

Методы indexOf() и lastIndexOf() возвращают индекс первого и последнего включения элемента в массиве. Например:

firstIndex имеет значение 0, так как первое включение строки «Tom» в массиве приходится на индекс 0, а последнее на индекс 3.

Если же элемент отсутствует в массиве, то в этом случае методы indexOf() и lastIndexOf() возвращают значение -1.

Проверка наличия элемента

Метод includes() проверяет, есть ли в массиве значение, переданное в метод через параметр. Если такое значение есть, то метод возвращает true , если значения в массиве нет, то возвращается false . Например:

В качестве второго параметра метод includes() принимает индекс, с которого надо начинать поиск:

В данном случае мы видим, что при поиске со 2-го индекса в массиве есть строка «Bob», тогда как начиная с 5-го индекса данная строка отсутствует.

Если если этот параметр не передается, то по умолчанию поиск идет с 0-го индекса.

При передаче отрицательного значения поиск идет с конца

every()

Метод every() проверяет, все ли элементы соответствуют определенному условию:

В метод every() в качестве параметра передается функция, которая представляет условие. Эта функция в качестве параметра принимает элемент и возвращает true (если элемент соответствует условию) или false (если не соответствует).

Если хотя бы один элемент не соответствует условию, то метод every() возвращает значение false .

В данном случае условие задается с помощью лямбда-выражения n => n > 0 , которое проверяет, больше ли элемент нуля.

Метод some() похож на метод every() , только он проверяет, соответствует ли хотя бы один элемент условию. И в этом случае метод some() возвращает true . Если элементов, соответствующих условию, в массиве нет, то возвращается значение false :

filter()

Метод filter() , как some() и every() , принимает функцию условия. Но при этом возвращает массив тех элементов, которые соответствуют этому условию:

forEach() и map()

Методы forEach() и map() осуществляют перебор элементов и выполняют с ними определенный операции. Например, используем метод метода forEach() для вычисления квадратов чисел в массиве:

Метод forEach() в качестве параметра принимает функцию, которая имеет один ппараметр — текущий перебираемый элемент массива. А в теле функции над этим элементом можно выполнить различные операции.

Консольный вывод программы:

Метод map() похож на метод forEach , он также в качестве параметра принимает функцию, с помощью которой выполняются операции над перебираемыми элементами массива, но при этом метод map() возвращает новый массив с результатами операций над элементами массива.

Например, применим метод map к вычислению квадратов чисел массива:

Функция, которая передается в метод map() получает текущий перебираемый элемент, выполняет над ним операции и возвращает некоторое значение. Это значение затем попадает в результирующий массив squares

Поиск в массиве

Метод find() возвращает первый элемент массива, который соответствует некоторому условию. В качестве параметр метод find принимает функцию условия:

В данном случае получаем первый элемент, который больше 10. Если элемент, соответствующий условию, не найден, то возвращается undefined .

Метод findIndex также принимает функцию условия, только возвращает индекс первого элемента массива, который соответствует этому условию:

Если элемент не найден, то возвращается число -1.

Метод flat и преобразование массива

Метод flat() упрощает массив с учетом указанной вложенности элементов:

То есть метод flat() фактически из вложенных массивов переводит элементы во внешний массив самого верхнего уровня. Однако мы видим, что элементы массива второго уровня вложенности перешли в массив первого уровня вложенности, но тем не менее по-прежнему находятся во вложенном массиве. Дело в том, что метод flat() по умолчанию применяется только к вложенным массивам первого уровня вложенности. Но мы можем передать в метод уровень вложености:

Если массив содержит вложенные массивы гораздо более глубоких уровней вложенности, или мы даже не знаем, какие уровни вложенности есть в массиве, но мы хотим, чтобы все элементы были преобразованы в один массив, то можно использовать значение Infinity :

JavaScript ES6: оператор расширения

JavaScript постоянно развивается, в нём появляются различные новшества и улучшения. Одно из таких новшеств, появившееся в ES6 — оператор расширения. Он выглядит как троеточие ( . ). Этот оператор позволяет разделять итерируемые объекты там, где ожидается либо полное отсутствие, либо наличие одного или нескольких аргументов. Сухие определения обычно бывает непросто понять без практических примеров. Поэтому рассмотрим несколько вариантов использования оператора расширения, которые помогут вникнуть в его сущность.

image

Пример №1: вставка массивов в другие массивы

Взгляните на этот код. Тут оператор расширения не используется:

Выше мы создали массив mid . Затем создан второй массив, arr , который содержит массив mid . В конце программы массив arr выводится в консоль. Как вы думаете, каким станет этот массив после добавления в него массива mid ? Взглянем на то, что выведет программа:

Вы думали, что так и будет?

Вставляя массив mid в массив arr , мы получили в итоге один массив, вложенный в другой. Если это именно то, что было нужно, то придираться тут не к чему. Однако, что если целью написания вышеприведённого кода было получение массива чисел от 1 до 6? Для того чтобы достичь этой цели, можно использовать оператор расширения. Вспомните о том, что этот оператор позволяет разделять массивы на отдельные элементы.

Рассмотрим следующий пример. Всё тут, за исключением одного места, точно такое же, как и в предыдущем фрагменте кода. Разница заключается в том, что теперь для того, чтобы вставить содержимое массива mid в массив arr , применяется оператор расширения:

Если этот код выполнить, то в результате будет выведено следующее:

Вспомните описание оператора расширения, приведённое в самом начале материала. Только что вы увидели его в действии. Как можно заметить, когда мы создаём массив arr и используем оператор расширения, применяя его к массиву mid , то, вместо вставки в один массив другого массива, как объекта, этот другой массив «разбивается на части». Разделение вставляемого массива в нашем случае означает, что все элементы этого массива, поодиночке, будут добавлены в массив arr . В результате, вместо конструкции из вложенных массивов, получился один массив, содержащий числа от 1 до 6.

Пример №2: математические вычисления

В JavaScript есть встроенный объект Math , который позволяет выполнять математические вычисления. В данном примере нас интересует метод Math.max() . Если вы с этим методом не знакомы, сообщаем, что он возвращает самое большое из переданных ему чисел, причём допустимо использовать его как без аргументов, так и с одним или несколькими аргументами. Вот несколько примеров:

Как видите, если требуется найти максимальное значение нескольких чисел, Math.max() нужно несколько параметров. К сожалению, если надо найти максимальный элемент числового массива, сам массив методу Math.max() передать нельзя. До появления в JS оператора расширения самым простым способом поиска максимального элемента в массиве с помощью Math.max() было использование метода apply() :

Выше представлена работающая конструкция, но выглядит всё это не очень-то приятно.

А вот как то же самое делается с помощью оператора расширения:

Вместо того, чтобы создавать функцию и использовать метод apply() для возвращения результата работы метода Math.max() , тут нужно лишь две строки кода. Оператор расширения «вытаскивает» из массива все его элементы и они поступают на вход метода Math.max() .

Пример №3: копирование массивов

В JS нельзя скопировать массив, просто приравняв новую переменную той, которая уже содержит существующий массив. Рассмотрим пример:

Если его выполнить, можно увидеть следующее:

На первый взгляд всё работает как надо, может показаться, что мы скопировали значения массива из переменной arr в переменную arr2 . Однако на самом деле произошло совсем другое. В JavaScript, в операциях присваивания объектов переменным (а массивы — это тоже объекты), оперируют ссылками на них, а не их значениями. Это означает, что в arr2 была записана та же ссылка, которая хранилась в arr . Другими словами, всё, что мы сделаем после этого с arr2 , повлияет и на arr (и наоборот). Взгляните на это:

Тут мы поместили новый элемент, строку d , в конец массива arr2 . Однако, выведя в консоль arr , можно увидеть, что массив, на который ссылается эта переменная, также изменился:

Надо заметить, что ничего страшного тут не происходит. Перед нами — стандартное поведение JS. А для того, чтобы действительно создать копию массива, можно воспользоваться оператором расширения. Вот пример использования этого оператора для копирования массивов. Код выглядит практически так же, как и в вышеприведённом примере. Однако здесь используется оператор расширения, применённый к исходному массиву, а вся эта конструкция помещена в квадратные скобки:

Выполнив этот код, можно увидеть, что выводит он то, чего мы от него и ожидаем:

В этом примере массив arr «разворачивается», в нашем распоряжении оказываются его отдельные элементы, которые попадают в новый массив, ссылка на который записывается в arr2 . Теперь можно делать с arr2 что угодно и это не повлияет на arr :

Опять же, причина, по которой это всё работает, заключается в том, что оператор расширения «вытаскивает» значения элементов массива arr и они попадают в новый массив arr2 . Таким образом, мы записываем в arr2 ссылку на новый массив, содержащий элементы из массива arr , а не ссылку на тот массив, на который ссылается переменная arr . Это и отличает данный пример от предыдущего.

Дополнительный пример: преобразование строки в массив

Напоследок — вот один интересный пример использования оператора расширения для преобразования строк в массивы. Здесь достаточно применить этот оператор к нужной строке, поместив всю эту конструкцию в пару квадратных скобок:

Итоги

Сегодня мы рассмотрели особенности работы с оператором расширения. Это — одна из новых возможностей JavaScript ES6, полезная мелочь, которая вполне способна улучшить читаемость кода и немного сократить его размер.

Уважаемые читатели! Пользуетесь ли вы оператором расширения в JavaScript?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *