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

Object.assign Метод

Давайте создадим объект человека и клонируем его с помощью Object.assign в примере ниже:

const person = {
  name: 'john',
  age: 35,
  interests: { javascript: true }
};
const clone = Object.assign({}, person);
console.log(clone);
// { name: 'john', age: 35, interests: { javascript: true } }

Печать значений из объекта клона показывает, что клон имеет те же свойства и значения, что и объект человека.

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

Слово мелкий является здесь ключевым. Давайте добавим приведенный ниже код в наш пример и посмотрим, что произойдет, если мы изменим значения в исходном объекте person:

...
person.name = 'jane';
person.age = 40;
person.interests.javascript = false;
console.log(person);
// { name: 'jane', age: 40, interests: { javascript: false } }
console.log(clone);
// { name: 'john', age: 35, interests: { javascript: false } }

Измененные значения name и age в объекте-персонаже не повлияли на объект-клон. Однако interest изменен на обоих объектах. Это ожидается?

Короткий ответ - да! При поверхностном клонировании значения всех свойств копируются с примитивными типами. Однако свойства Object и Array являются ссылками, и связанные объекты / массивы не будут скопированы в неглубокий клон. Вместо этого ссылки копируются. interest - это вложенный объект внутри объекта person, и только ссылка на него копируется в clone. Оба объекта имеют ссылку на один и тот же объект interest, поэтому изменение свойства интереса с помощью объекта person напрямую изменит интерес клонированного объекта и наоборот.

Чтобы решить эту проблему, необходимо выполнять глубокое клонирование вместо поверхностного клонирования. Глубокое клонирование не будет рассматриваться в этой статье, но это хороший кандидат для следующей.

Object.assign - мощная функция, у которой много других применений, но давайте сосредоточимся на поверхностном клонировании и рассмотрим альтернативные методы.

Оператор распространения (синтаксис ...) Метод

Оператор распространения поставляется со стандартом ECMAScript 2018 и теперь поддерживается большинством современных браузеров и NodeJS по умолчанию. Его использование довольно простое. Просто замените строку клонирования в приведенном выше примере на следующую:

const clone = { ...person };

Вот и все! Оператор распространения удобочитаем и элегантен. Он передает свойства объекта person в пустой литерал объекта.

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

Метод Лодаша

В большинстве случаев в наших приложениях рекомендуется использовать служебную библиотеку. Хотя JavaScript с годами становится все более и более мощным, его стандартный набор инструментов не покрывает все наши амбициозные требования. На этом этапе к действию присоединяются служебные библиотеки. Lodash - популярный выбор. Вот как это делается в _:

const _ = require('lodash');
...
const clone = _.clone(person);

Опять же, читабельно и элегантно. Lodash также поддерживает глубокое клонирование "из коробки" своим cloneDeep методом.

Заключение

Мы продемонстрировали 3 способа поверхностного клонирования:

Object.assign({}, person); // Old-school JS
const clone = { ...person };             // Spread operator
const clone = _.clone(person);           // Lodash method

Какой метод вы предпочитаете? Вы используете другие альтернативы? Напишите, пожалуйста, в комментариях. Не забудьте поддержать вас аплодисментами и репостами, если вам понравилась статья. Удачного кодирования!