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

Как копировать объект

  • автор:

Копирование объектов и ссылки

Одно из фундаментальных отличий объектов от примитивов заключается в том, что объекты хранятся и копируются «по ссылке», тогда как примитивные значения: строки, числа, логические значения и т.д. – всегда копируются «как целое значение».

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

Давайте начнём с примитива, такого как строка.

Здесь мы помещаем копию message во phrase :

let message = "Привет!"; let phrase = message;

В результате мы имеем две независимые переменные, каждая из которых хранит строку «Привет!» .

Вполне очевидный результат, не так ли?

Объекты ведут себя иначе.

Переменная, которой присвоен объект, хранит не сам объект, а его «адрес в памяти» – другими словами, «ссылку» на него.

Давайте рассмотрим пример такой переменной:

let user = < name: "John" >;

И вот как это на самом деле хранится в памяти:

Объект хранится где-то в памяти (справа от изображения), в то время как переменная user (слева) имеет лишь «ссылку» на него.

Мы можем думать о переменной объекта, такой как user , как о листе бумаги с адресом объекта на нем.

Когда мы выполняем действия с объектом, к примеру, берём свойство user.name , движок JavaScript просматривает то, что находится по этому адресу, и выполняет операцию с самим объектом.

Теперь вот почему это важно.

При копировании переменной объекта копируется ссылка, но сам объект не дублируется.

let user = < name: "John" >; let admin = user; // копируется ссылка

Теперь у нас есть две переменные, каждая из которых содержит ссылку на один и тот же объект:

Как вы можете видеть, все ещё есть один объект, но теперь с двумя переменными, которые ссылаются на него.

Мы можем использовать любую переменную для доступа к объекту и изменения его содержимого:

let user = < name: 'John' >; let admin = user; admin.name = 'Pete'; // изменено по ссылке из переменной "admin" alert(user.name); // 'Pete', изменения видны по ссылке из переменной "user"

Это как если бы у нас был шкафчик с двумя ключами, и мы использовали один из них ( admin ), чтобы войти в него и внести изменения. А затем, если мы позже используем другой ключ ( user ), мы все равно открываем тот же шкафчик и можем получить доступ к изменённому содержимому.

Сравнение по ссылке

Два объекта равны только в том случае, если это один и тот же объект.

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

let a = <>; let b = a; // копирование по ссылке alert( a == b ); // true, обе переменные ссылаются на один и тот же объект alert( a === b ); // true

И здесь два независимых объекта не равны, даже если они выглядят одинаково (оба пусты):

let a = <>; let b = <>; // два независимых объекта alert( a == b ); // false

Для сравнений типа obj1 > obj2 или для сравнения с примитивом obj == 5 объекты преобразуются в примитивы. Очень скоро мы изучим, как работают преобразования объектов, но, по правде говоря, такие сравнения требуются очень редко и обычно они появляются в результате ошибок программиста.

Клонирование и объединение, Object.assign

Итак, копирование объектной переменной создаёт ещё одну ссылку на тот же объект.

Но что, если нам всё же нужно дублировать объект? Создать независимую копию, клон?

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

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

let user = < name: "John", age: 30 >; let clone = <>; // новый пустой объект // давайте скопируем все свойства user в него for (let key in user) < clone[key] = user[key]; >// теперь clone это полностью независимый объект с тем же содержимым clone.name = "Pete"; // изменим в нём данные alert( user.name ); // все ещё John в первоначальном объекте

Также мы можем использовать для этого метод Object.assign.

Object.assign(dest, [src1, src2, src3. ])
  • Первый аргумент dest — целевой объект.
  • Остальные аргументы src1, . srcN (может быть столько, сколько необходимо) являются исходными объектами
  • Метод копирует свойства всех исходных объектов src1, . srcN в целевой объект dest . Другими словами, свойства всех аргументов, начиная со второго, копируются в первый объект.
  • Возвращает объект dest .

Например, мы можем использовать его для объединения нескольких объектов в один:

let user = < name: "John" >; let permissions1 = < canView: true >; let permissions2 = < canEdit: true >; // копируем все свойства из permissions1 и permissions2 в user Object.assign(user, permissions1, permissions2); // теперь user =

Если скопированное имя свойства уже существует, оно будет перезаписано:

let user = < name: "John" >; Object.assign(user, < name: "Pete" >); alert(user.name); // теперь user =

Мы также можем использовать Object.assign для замены цикла for..in для простого клонирования:

let user = < name: "John", age: 30 >; let clone = Object.assign(<>, user);

Он копирует все свойства user в пустой объект и возвращает его.

Также существуют и другие методы клонирования объекта. Например, с использованием оператора расширения clone = <. user>, рассмотренного далее в учебнике.

Вложенное клонирование

До сих пор мы предполагали, что все свойства user примитивныe. Но свойства могут быть и ссылками на другие объекты. Что с ними делать?

Например, есть объект:

let user = < name: "John", sizes: < height: 182, width: 50 >>; alert( user.sizes.height ); // 182

Теперь недостаточно просто скопировать clone.sizes = user.sizes , потому что user.sizes – это объект, он будет скопирован по ссылке. Таким образом, clone и user будут иметь общий объект sizes :

let user = < name: "John", sizes: < height: 182, width: 50 >>; let clone = Object.assign(<>, user); alert( user.sizes === clone.sizes ); // true, тот же объект // user и clone обладают общим свойством sizes user.sizes.width++; // изменяем свойства в первом объекте alert(clone.sizes.width); // 51, видим результат в другом

Чтобы исправить это, мы должны использовать цикл клонирования, который проверяет каждое значение user[key] и, если это объект, тогда также копирует его структуру. Это называется «глубоким клонированием».

Мы можем реализовать глубокое клонирование, используя рекурсию. Или, чтобы не изобретать велосипед заново, возьмите готовую реализацию, например _.cloneDeep(obj) из библиотеки JavaScript lodash.

Также мы можем использовать глобальный метод structuredClone(), который позволяет сделать полную копию объекта. К сожалению он поддерживается только современными браузерами. Здесь можно ознакомиться с поддержкой этого метода.

Объекты, объявленные как константа, могут быть изменены

Важным побочным эффектом хранения объектов в качестве ссылок является то, что объект, объявленный как const , может быть изменён.

const user = < name: "John" >; user.name = "Pete"; // (*) alert(user.name); // Pete

Может показаться, что строка (*) вызовет ошибку, но, это не так. Значение user это константа, оно всегда должно ссылаться на один и тот же объект, но свойства этого объекта могут свободно изменяться.

Другими словами, const user выдаст ошибку только в том случае, если мы попытаемся задать user=. в целом.

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

Итого

Объекты присваиваются и копируются по ссылке. Другими словами, переменная хранит не «значение объекта», а «ссылку» (адрес в памяти) на это значение. Таким образом, копирование такой переменной или передача её в качестве аргумента функции копирует эту ссылку, а не сам объект.

Все операции с использованием скопированных ссылок (например, добавление/удаление свойств) выполняются с одним и тем же объектом.

Чтобы создать «реальную копию» (клон), мы можем использовать Object.assign для так называемой «поверхностной копии» (вложенные объекты копируются по ссылке) или функцию «глубокого клонирования», такую как _.cloneDeep(obj).

Поверхностное и глубокое копирование

При копировании объектов и массивов в JavaScript, данные копируются только на один уровень вглубь.

Время чтения: меньше 5 мин

Открыть/закрыть навигацию по статье

  1. Кратко
  2. Как понять
    1. Проблема поверхностного копирования
    2. Как получить глубокую копию

    Обновлено 25 июля 2023

    Кратко

    Скопировать ссылку «Кратко» Скопировано

    При копировании объектов или массивов JavaScript копирует данные только на один уровень вглубь. Этот тип копирования называется поверхностным (shallow).

    Если необходимо полностью скопировать сложную структуру данных, например, массив с объектами, то нужно делать глубокое (deep) или полное копирование данных. JavaScript не содержит функций для глубокого копирования, лучший вариант сделать глубокую копию — сериализовать структуру в JSON и тут же распарсить.

    Как понять

    Скопировать ссылку «Как понять» Скопировано

    Проблема поверхностного копирования

    Скопировать ссылку «Проблема поверхностного копирования» Скопировано

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

     const itemsInCart = [ < product: 'Носки', quantity: 3 >, < product: 'Штаны', quantity: 1 >, < product: 'Кепка', quantity: 1 >,] const clonedCart = [. itemsInCart] const itemsInCart = [  product: 'Носки', quantity: 3 >,  product: 'Штаны', quantity: 1 >,  product: 'Кепка', quantity: 1 >, ] const clonedCart = [. itemsInCart]      

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

     clonedCart[1].quantity = 5 console.log(clonedCart)// [// < product: 'Носки', quantity: 3 >,// < product: 'Штаны', quantity: 5 >,// < product: 'Кепка', quantity: 1 >,// ] console.log(itemsInCart)// [// < product: 'Носки', quantity: 3 >,// < product: 'Штаны', quantity: 5 >,// < product: 'Кепка', quantity: 1 >,// ] clonedCart[1].quantity = 5 console.log(clonedCart) // [ // < product: 'Носки', quantity: 3 >, // < product: 'Штаны', quantity: 5 >, // < product: 'Кепка', quantity: 1 >, // ] console.log(itemsInCart) // [ // < product: 'Носки', quantity: 3 >, // < product: 'Штаны', quantity: 5 >, // < product: 'Кепка', quantity: 1 >, // ]      

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

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

     console.log(itemsInCart[1] === clonedCart[1])// true console.log(itemsInCart[1] === clonedCart[1]) // true      

    Результат поверхностного копирования массива

    Как получить глубокую копию

    Скопировать ссылку «Как получить глубокую копию» Скопировано

    В JavaScript есть функция structuredClone() для глубокого копирования массивов или объектов. На странице с документацией можно проверить доступность этой функции для разных версий: например, она доступна в NodeJS, начиная с версии 17.0.0.

     const deep = structuredClone(itemsInCart)console.log(itemsInCart[1] === deep[1])// false const deep = structuredClone(itemsInCart) console.log(itemsInCart[1] === deep[1]) // false      

    Существуют и другие способы сделать глубокое копирование. Можно написать функцию глубокого копирования вручную. Скорее всего ваша функция будет рекурсивной, и она будет работать только для конкретных данных — написать универсальную функцию не так-то просто.

    Можно воспользоваться готовой библиотекой. Например, функцию глубокого копирования содержит популярная библиотека утилит lodash. Функция гарантировано работает в подавляющем большинстве случаев, потому что используется в десятках тысяч проектов каждый день. Исходный код библиотеки открыт, можно изучить исходный код функции глубокого копирования.

     import cloneDeep from 'lodash.clonedeep' const deep = cloneDeep(itemsInCart)console.log(itemsInCart[1] === deep[1])// false import cloneDeep from 'lodash.clonedeep' const deep = cloneDeep(itemsInCart) console.log(itemsInCart[1] === deep[1]) // false      

    Ещё один способ глубокого копирования звучит достаточно глупо — нужно сериализовать копируемый объект в JSON и тут же распарсить его. В результате появится полная копия объекта:

     const deep = JSON.parse(JSON.stringify(itemsInCart))console.log(itemsInCart[1] === deep[1])// false const deep = JSON.parse(JSON.stringify(itemsInCart)) console.log(itemsInCart[1] === deep[1]) // false      

    Результат глубокого копирования массива

    У этого метода есть ограничение — копируемые данные должны быть сериализуемы.

    Вот примеры несериализуемых данных: примитив undefined, функция, symbol — при вызове JSON.stringify получаем undefined

    Массивы и объекты — сериализуемы. Что будет если у них в качестве ключа или значения будут несериализуемые данные?

    • для массивов: такие значения будут превращены в null;
    • для объектов: такие значения будут опущены, а если symbol является ключом объекта, то он будет проигнорирован, даже при использовании функции replacer.
     const arr = [ undefined, function() < console.log('aaa') >, Symbol("foo"),]const copyArr = JSON.parse(JSON.stringify(arr)) console.log(copyArr)// [null, null, null] const obj =  a: undefined, method: () => <>, [Symbol("foo")]: "foo",>const copyObj = JSON.parse(JSON.stringify(obj), function(k, v)  if (typeof k === 'symbol')  return 'символ'; > return v;>) console.log(copyObj)// <> const arr = [ undefined, function()  console.log('aaa') >, Symbol("foo"), ] const copyArr = JSON.parse(JSON.stringify(arr)) console.log(copyArr) // [null, null, null] const obj =  a: undefined, method: () => >, [Symbol("foo")]: "foo", > const copyObj = JSON.parse(JSON.stringify(obj), function(k, v)  if (typeof k === 'symbol')  return 'символ'; > return v; >) console.log(copyObj) // <>      

    Клонирование и копирование — JS: Объекты

    Клонирование объектов — еще одна часто встречающаяся операция в разработке, особенно во фронтенде. При клонировании создается копия исходного объекта — то есть новый объект, наполненный теми же данными.

    В JavaScript клонирование можно эмулировать с помощью Object.assign() . Для этого нужно первым параметром передать пустой объект, а вторым — тот, который нужно клонировать:

    const user =  name: 'Tirion', email: 'support@hexlet.io', age: 44 >; // Данные из user копируются во вновь созданный объект const copyOfUser = Object.assign(<>, user); user === copyOfUser; // false 

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

    Клонирование также выполняют с помощью функции clone() библиотеки lodash. Результат выполнения этой функции идентичен примерам выше, но благодаря своему имени, она лучше выражает смысл операции:

    import _ from 'lodash'; const user =  name: 'Tirion', email: 'support@hexlet.io', age: 44 >; const copyOfUser = _.clone(user); 

    Клонирование способами выше не затрагивает вложенные объекты. Они оказываются в новом объекте по ссылке из старого:

    const user =  company:  name: 'Hexlet' > >; const copyOfUser = Object.assign(<>, user); // Это тот же объект user.company === copyOfUser.company; // true user.company.createdAt = 2012; console.log(copyOfUser.company.createdAt); // 2012 

    Такое клонирование называется поверхностным (shallow copying). Очень важно запомнить, что именно это имеют ввиду в JavaScript, когда употребляют термин «клонирование». Поверхностное клонирование подходит для многих ситуаций, но иногда его недостаточно. В таких случаях нужно использовать полное или глубокое клонирование (deep copying).

    В JavaScript есть встроенный метод structuredClone() , c помощью которого можно выполнить глубокое копирование объектов:

    const user =  company:  name: 'Hexlet' > >; const copyOfUser = structuredClone(user); user.company === copyOfUser.company; // false 

    Открыть доступ

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

    • 130 курсов, 2000+ часов теории
    • 1000 практических заданий в браузере
    • 360 000 студентов

    Наши выпускники работают в компаниях:

    Копирование объектов в JavaScript

    Объекты это основа JavaScript’а. Сам по себе, объект это набор данных, где каждая единица информации является связью между ключом (или именем) и значением. Почти все объекты в JavaScript это экземпляры Object, который стоит на вершине цепочки прототипов.

    ��Мой Твиттер — там много из мира фронтенда, да и вообще поговорим��. Подписывайтесь, будет интересно: ) ✈️

    Введение

    Как вы уже наверное знаете, оператор назначения не создаёт копию объекта, а только делает отсылку к нему, давайте посмотрим на следующий код:

    let obj = a: 1, 
    b: 2,
    >;
    let copy = obj;

    obj.a = 5;
    console.log(copy.a);
    // Результат
    // a = 5;

    Тут переменная obj это контейнер для нового объекта. Переменная copy указывает на этот же объект и является своеобразной отсылкой к нему. Так что, просто напросто, объект < a: 1, b: 2, >как бы говорит нам: Есть два способа получить ко мне доступ. Вы можете получить его через переменную obj или через переменную copy , в обоих случаях получите возможность работать со мной и всё, что бы вы не делали этими способами, отобразится на мне.

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

    Простой и наивный способ копирования объектов

    Простой способ копирования объектов заключается в том, что пройтись циклом по оригинальному объекту и скопировать каждое свойство по очереди. Давайте взглянем на такой код:

    function copy(mainObj) let objCopy = <>; // objCopy будет хранить копию mainObj 
    let key;

    for (key in mainObj) objCopy[key] = mainObj[key]; // копирует каждое свойство objCopy
    >
    return objCopy;
    >

    const mainObj = a: 2,
    b: 5,
    c: x: 7,
    y: 4,
    >,
    >

    console.log(copy(mainObj));

    Проблемы при таком методе:

    objCopy объект имеет другой метод Object.prototype , отличающийся от mainObj прототип метода, который не совсем то, что нам нужно. Нам нужна точная копия оригинального объекта.

    Дескрипторы свойств не скопированы. Перезаписываемый дескриптор со значением выставленным на false , будет выставлен на true в объекте objCopy .

    Код выше копирует только перечисляемые свойства объекта mainObj .

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

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

    Поверхностно скопированным объектом, можно называть объект, когда исходные top-level (самые первые в иерархии объекта) свойства скопированы без какой-либо отсылки и существует исходное свойство, чьё значение это объект и он скопирован уже как отсылка. А если исходное значение это отсылка к объекту, то он копирует только отсылку к значению целевого объекта.

    Поверхностная копия скопирует только top-level свойства, но вложенные объекты будут использоваться между оригиналом, так и копией.

    Используем метод Object.assign()

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

    let obj = a: 1, 
    b: 2,
    >;
    let objCopy = Object.assign(<>, obj);
    console.log(objCopy);
    // Результат -

    Отлично, пока что все работает как надо. Мы сделали копию obj . Давайте посмотрим на наличие иммутабельности:

    let obj = a: 1, 
    b: 2,
    >;
    let objCopy = Object.assign(<>, obj);

    console.log(objCopy); // результат -
    objCopy.b = 89;
    console.log(objCopy); // результат -
    console.log(obj); // результат -

    В коде выше, мы изменили значение свойства b в objCopy объекте на 89 и когда мы вывели измененный objCopy объект в консоль, изменения применились только к objCopy . Последняя строчка кода проверяет то, что объект obj до сих пор не тронут и не изменён. Это подразумевает то, что мы успешно создали копию исходного объекта без каких либо отсылок к нему.

    Подводные камни Object.assign()

    Не так быстро! Пока мы успешно создали копию и все вроде бы отлично работает, вспомните то, что мы обсуждали поверхностное копирование? Давайте посмотрим на пример ниже:

    let obj = a: 1, 
    b: c: 2,
    >,
    >
    let newObj = Object.assign(<>, obj);
    console.log(newObj); // < a: 1, b: < c: 2>>

    obj.a = 10;
    console.log(obj); // < a: 10, b: < c: 2>>
    console.log(newObj); // < a: 1, b: < c: 2>>

    newObj.a = 20;
    console.log(obj); // < a: 10, b: < c: 2>>
    console.log(newObj); // < a: 20, b: < c: 2>>

    newObj.b.c = 30;
    console.log(obj); // < a: 10, b: < c: 30>>
    console.log(newObj); // < a: 20, b: < c: 30>>

    // Обратите внимание: newObj.b.c = 30; Читаем дальше почему

    Что? Почему obj.b.c = 30?

    Отлично, вот мы попались в ловушку с Object.assign() . Object.assign делает только поверхностную копию. А newObj.b и obj.b вместе отсылаются к одному и тому объекту, так как отдельные копии не создавались, а была сделана отсылка к объекту. Любое изменение сделанное на любом свойстве объекта, применится ко всем отсылкам использующим объект. Как это исправить? Читаем дальше, там будет исправление этой проблемы.

    Обратите внимание: свойства в цепочке прототипов и неперечисляемые свойства не могут быть скопированы. Как тут:

    let someObj = a: 2,
    >

    let obj = Object.create(someObj, <
    b: value: 2,
    >,
    c: value: 3,
    enumerable: true,
    >,
    >);

    let objCopy = Object.assign(<>, obj);
    console.log(objCopy); //

    someObj находится в цепочке прототипов obj , поэтому он не скопируется.

    Свойство b это неперечисляемое свойство.

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

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

    Глубокая копия продублирует каждый объект на пути копирования. Оригинал и скопированный объект не будут иметь ничего общего и совместно использоваться не будут, в общем, это будет копия оригинала. А вот и решение проблемы с который мы столкнулись при использовании Object.assign() . Давайте посмотрим.

    Использование JSON.parse(JSON.stringify(object));

    Этот подход решает предыдущую проблему. Теперь newObj.b это копия, а не отсылка к оригинальному объекту! Вот так делается глубокое копирование объектов. Пример:

    let obj = < 
    a: 1,
    b: <
    c: 2,
    >,
    >

    let newObj = JSON.parse(JSON.stringify(obj));

    obj.b.c = 20;
    console.log(obj); // < a: 1, b: < c: 20 >>
    console.log(newObj); // < a: 1, b: < c: 2 >> (Новый нетронутый объект!)

    Небольшая загвоздка

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

    Копируем методы объекта

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

    let obj = name: 'scotch.io', 
    exec: function exec() return true;
    >,
    >

    let method1 = Object.assign(<>, obj);
    let method2 = JSON.parse(JSON.stringify(obj));

    console.log(method1); //Object.assign(<>, obj)
    /* result
    exec: function exec() return true;
    >,
    name: "scotch.io"
    >
    */


    console.log(method2); // JSON.parse(JSON.stringify(obj))
    /* result
    name: "scotch.io"
    >
    */

    Результат показывает нам то, что Object.assign() можно использовать для копирования методов, а JSON.parse(JSON.stringify(obj)) , к сожалению, нет.

    Копирование циклических объектов

    Циклические объекты — это объекты, у которых есть свойства, ссылающиеся сами на себя. Давайте применим уже известные методы копирования для создания копий циклических объектов и посмотрим, как они сейчас сработают.

    Применяем JSON.parse(JSON.stringify(object))

    Давайте попробуем JSON.parse(JSON.stringify(object)):

    // Циклический объект
    let obj = <
    a: 'a',
    b: <
    c: 'c',
    d: 'd',
    >,
    >

    obj.c = obj.b;
    obj.e = obj.a;
    obj.b.c = obj.c;
    obj.b.d = obj.b;
    obj.b.e = obj.b.c;

    let newObj = JSON.parse(JSON.stringify(obj));

    console.log(newObj);

    В общем, такой подход не работает для циклических объектов.

    Используем Object.assign()

    Давайте его попробуем:

    // Циклический объект
    let obj = <
    a: 'a',
    b: <
    c: 'c',
    d: 'd',
    >,
    >

    obj.c = obj.b;
    obj.e = obj.a;
    obj.b.c = obj.c;
    obj.b.d = obj.b;
    obj.b.e = obj.b.c;

    let newObj2 = Object.assign(<>, obj);

    console.log(newObj2);

    А вот и результат:

    Object.assign() отлично работает для поверхностного копирования циклических объектов, но не будет работать для создания глубокой копии. Посмотрите на circular object tree в консоли вашего браузера. Я уверен, что вы найдете много всего интересного в том, что там происходит.

    Используем элементы Spread (…) (Или оператор расширения)

    В ES6 есть элементы rest для деструктурирующего присваивания и spread элементы для работы с литерал массивами. Давайте посмотрим на то, как сработает элемент spread на массиве:

    const array = [ 
    "a",
    "c",
    "d", four: 4
    >,
    ];
    const newArray = [. array];
    console.log(newArray);
    // Result
    // ["a", "c", "d", < four: 4 >]

    Использование оператора расширения на свойствах объекта, создаёт копии собственных перечисляемых свойств из исходного объекта в один целевой объект. Пример ниже показывает, как легко можно скопировать объект. (spread сейчас находится на 4 стадии утверждения ECMAScript https://github.com/tc39/proposal-object-rest-spread).

    let obj = one: 1, 
    two: 2,
    >

    let newObj = < . obj >;

    Обратите внимание, что этот подход действенен для поверхностной копии.

    Заключение

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

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

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