02. Copying Objects

Object.assign

Функция Object.assign получает список объектов и копирует в первый target свойства из остальных. При этом последующие свойства перезаписывают предыдущие. Этот прием так же можно использовать для поверхностного копирования.

Object.assign(target, src1, src2...)
const user = { name: "Вася" };
const visitor = { isAdmin: false, visits: true };
const admin = { isAdmin: true };
Object.assign(user, visitor, admin); // name: Вася, visits: true, isAdmin: true

// clone = пустой объект + все свойства user
const user = { name: "Вася", isAdmin: false };
const clone = Object.assign({}, user);

Особенности:

  • Object.assign копирует как строковые ключи, так и символьные

  • Копируются только собственные перечисляемые свойства. Унаследованные и неперечисляемые свойства игнорируются.

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

  • Запись свойства в target - это обычная операция присваивания свойства. Функции setter-ы не копируются.

  • Нельзя скопировать метод, использующий super в другой объект.

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

function copyAllProperties(target, ...sources) {
  for (const source of sources) {
    for (const key of Reflect.ownKeys(source)) {
      const desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
  return target;
}

Способ 2:

const clone = Object.create(
  Object.getPrototypeOf(obj),
  Object.getOwnPropertyDescriptors(obj)
);

Метод Object.assign можно использовать для заполнения значений по умолчанию:

const DEFAULTS = {
    logLevel: 0,
    outputFormat: 'html'
};

function processContent(options) {
    options = Object.assign({}, DEFAULTS, options); // (A)
    ···
}

A method that uses super is firmly connected with its home object (the object it is stored in). There is currently no way to copy or move such a method to a different object.

Deep copy

Для создания полностью идентичной копии другого объекта необходимо выполнить два шага:

  • Копия должна иметь тот же прототип

  • Копия должна иметь те же атрибуты с теми же значениями, что и оригинал.

function copyObject(orig) {
  // 1. copy has same prototype as orig
  const copy = Object.create(Object.getPrototypeOf(orig));
  // 2. copy has all of orig’s properties
  copyOwnPropertiesFrom(copy, orig);
  return copy;
}

function copyOwnPropertiesFrom(target, source) {
  Object.getOwnPropertyNames(source).forEach(function(propKey) {
    // (1), (2)
    const desc = Object.getOwnPropertyDescriptor(source, propKey); // (3)
    Object.defineProperty(target, propKey, desc); // (4)
  });
  return target;
}

Шаги алгоритма:

  1. Get an array with the keys of all own properties of source.

  2. Iterate over those keys.

  3. Retrieve a property descriptor.

  4. Use that property descriptor to create an own property in target.

Last updated