Как сделать клон массива js

Обновлено: 05.07.2024

Для того, чтобы получить копию объекта, как сложного типа данных, придется приложить некоторое количество усилий, т.к. в отличие от примитивных типов Number, String, Boolean, которые чаще всего являются значениями свойств объекта, обычное присваивание не создаст нам второй объект с такими же точно данными. Давайте посмотрим, почему.

Способ 1. Создание дополнительной ссылки на объект

Начнем с примитивов, чтобы была видна разница.

Из примера видно, что каждая из числовых или строковых переменных, которые имели при присвоении (копировании) одно и то же значение, впоследствии изменяется абсолютно автономно. Обратите внимание, что, если значения этих типов равны, то равны и сами переменные.

Давайте теперь то же самое проделаем с объектом. То есть мы просто присвоим объект в другую переменную. А затем изменим одно свойство в исходном объекте и в его клоне, или копии.

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

Это указывает на то, что обе переменные ведут на один и тот же адрес в памяти компьютера, и при присвоении происходит передача объекта по ссылке. То есть 2 переменные ссылаются на одно и то же место в оперативной памяти, занятое нашим объектом, поэтому нет ничего удивительного, что он изменяется и с помощью исходной переменной, и с помощью копии.

Передача объекта по ссылке

Поэтому нельзя назвать копией вторую переменную. Это больше похоже на телефонную связь с одним абонентом. Номер его телефона может храниться в любом количестве других девайсов, но дозваниваться (ссылаться в случае объектов в JS) с них будут всегда на одно и то же устройство с этим номером. Поэтому слова "способ 1" в заголовке перечеркнуты, т.к. этот процесс не является копированием с получением 2-х разных объектов с идентичными свойствами и методами.

Есть еще один нюанс, касающийся сравнения объектов. Когда мы пишем строки вида obj1===obj2 , то true вернется только в случае, рассмотренном выше, когда переменные ссылаются на один и тот же объект Если же объекты являются идентичными, но созданы вручную при написании кода или любым из перечисленных ниже способов, то сравнение на равенство вернет false , т.к. каждый объект имеет свой собственный адрес в памяти компьютера. И они не совпадают!

Оператор spread для копирования объектов

Способ 2. Быстрое копирование одноуровневого объекта оператором spread

В том случае, когда у нас есть объект, содержащий только свойства (ключи), значениями которых являются примитивные типы данных (не объекты), то можно использовать простой способ копирования этих объектов, основанный на spread-операторе (оператор расширения):

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

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

Но если вы, изменяя копию, меняете и оригинальный объект без намерений сделать это, то вам явно нужно взглянуть на типы копирования, которые мы рассмотрим в этой статье!

Вначале нам нужно понять концепцию передачи по значению и передачи по ссылке.

Передача по значению и по ссылке

Есть два способа передачи и копирования: один по значению, а другой по ссылке. Когда вы копируете что-то по значению, это означает, что вы создаете новое отдельное и независимое значение, подобное оригиналу - глубокая копия( Deep Copy ).

Но когда вы копируете что-то по ссылке, вы создаете просто псевдоним оригинала, а не новую или независимую копию - поверхностную копию( Shallow copy ).

Глубокое копирование

Когда вы создаете глубокую копию, вы создаете идентичную копию исходного элемента с его свойствами.

Оригинал и копия не связаны, что означает, если вы изменили свойства оригинала, это не повлияет на скопированный элемент и не изменит его.

Поверхностное копирование

С другой стороны, когда вы создаете поверхностную копию, вы просто помещаете ссылку на оригинальный объект в другую переменную.

Таким образом, когда вы меняете оригинал, это также повлияет и изменит скопированный, и то же самое, если вы изменили что-то в скопированном элементе, это же что-то изменится и в оригинале.


Почему нельзя использовать = ? Посмотрим, что может произойти:

Оба объекта выдают одно и то же. На данный момент никаких проблем. Рассмотрим, что произойдет после редактирования второго объекта:

obj2 был изменен, однако изменения коснулись и obj . Причина заключается в том, что объекты являются ссылочными типами. Поэтому при использовании = , указатель копируется в область занимаемой памяти. Ссылочные типы не содержат значений, они являются указателем на значение в памяти.

С помощью spread можно клонировать объект. Обратите внимание, что копия будет неглубокой. На момент публикации этого руководства оператор spread для клонирования объектов находился на стадии 4, соответственно официально он не указан в спецификациях. Поэтому для того, чтобы его использовать, нужно выполнить компиляцию с Babel (или чем-то подобным).

Object.assign , выпущенный официально, также создает неглубокую копию объекта.

Этот способ предоставляет глубокую копию. Стоит упомянуть, что это быстрый и грязный способ глубокого клонирования объекта. В качестве более надежного решения рекомендуется использовать что-то вроде lodash.

  • JSON.stringify/parse работает только с литералом Number, String и Object без функции или свойства Symbol.
  • deepClone работает со всеми типами, а функция и символ копируются по ссылке.

При использовании spread для копирования объекта создается неглубокая копия. Если массив является вложенным или многомерным, этот способ не будет работать. Рассмотрим пример:

Таким образом, клонированный объект был изменен с добавлением city. В результате получаем:

Неглубокая копия предполагает копирование первого уровня и ссылается на более глубокие уровни.

Возьмем тот же пример, но применим глубокую копию с использованием JSON:

Глубокая копия является копией для вложенных объектов. Однако иногда достаточно использования неглубокой копии.

К сожалению, на данный момент нельзя написать тестирование для spread, поскольку официально он не указан в спецификации. Однако результат показывает, что Object.assign намного быстрее, чем JSON . Тест на производительность можно найти здесь.

Стоит отметить, что Object.assign — это функция, которая модифицирует и возвращает целевой объект. В данном примере при использовании:

<> - это модифицируемый объект. В этой точке на целевой объект не ссылаются никакие переменные, но поскольку Object.assign возвращает целевой объект, то можно сохранить полученный присвоенный объект в переменную cloneFood . Данный пример можно изменить следующим образом:

Очевидно, что значение beef в объекте food неверно, поэтому нужно назначить правильное значение beef с помощью Object.assign . На самом деле мы не используем возвращаемое значение функции, а изменяем целевой объект, на который ссылаемся с помощью константы food .

С другой стороны, Spread — это оператор, который копирует свойства одного объекта в новый объект. При репликации приведенного выше примера с помощью spread для изменения переменной food.

. мы получаем ошибку в результате использования spread для создания новых объектов и, следовательно, присваиваем новый объект для food , который был объявлен с помощью const , что недопустимо. Поэтому можно либо объявить новую переменную для хранения нового объекта, как показано ниже:

Мне нужно сделать клон без, используя slice , json.parse и другие методы.

На данный момент код работает, но не клонирует объекты:

Просто клонируйте вот так: let clone = JSON.parse(JSON.stringify(['1',,['3',]‌​,'5']))

Get Off My Lawn

что вы имеете в виду под другими методами? как узнать, является ли объект массивом?

Ответы 2

Вы можете проверить, предоставлен ли объект, и если да, выполняется еще одна проверка для массива. Затем верните либо клонированный массив, либо объект, либо само значение.

Вот простая реализация без методов массива:

Обратите внимание, что это работает только для простых типов данных. Как только вы начнете работать с датами, объектами регулярных выражений, наборами, картами и т. д., Вам понадобится гораздо больше логики. Также подумайте о ссылках на себя и функциях, а также о том, как с ними обращаться.

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

Другие вопросы по теме

Похожие вопросы

Как открыть веб-консоль, такую ​​как консоль chrome, на стороне предварительного просмотра кода visual studio и динамически видеть изменения javascript?

Читайте также: