Object.assign()

Статичний метод Object.assign() (присвоїти) копіює всі перелічувані власні властивості від одного чи більше донорських об'єктів до цільового об'єкта. Він повертає модифікований цільовий об'єкт.

Спробуйте його в дії

Синтаксис

Object.assign(target, source1)
Object.assign(target, source1, source2)
Object.assign(target, source1, source2, /* …, */ sourceN)

Параметри

target

Цільовий об'єкт — об'єкт, на який буде перенесено властивості з донорів, і який буде повернено після змін.

sourceN

Донорські об'єкти — об'єкти, що містять властивості, які потрібно скопіювати.

Повернене значення

Цільовий об'єкт.

Опис

Властивості цільового об'єкта перезаписуються властивостями донорів, якщо вони мають однакові ключі. Властивості наступних донорських об'єктів перезаписують властивості попередніх (в цільовому об'єкті).

Метод Object.assign() копіює до цільового об'єкта лише перелічувані та власні властивості донорських об'єктів. Він використовує [[Get]] на донорі та [[Set]] на цільовому об'єкті, тобто він викликає гетери й сетери. Інакше кажучи, він саме присвоює властивості, замість копіювання чи оголошення нових. Це може робити його непридатним для злиття нових властивостей у прототип, якщо донори для злиття містять гетери.

Для копіювання оголошень властивостей (включно з їхньою перелічуваністю) у прототипи слід натомість використовувати Object.getOwnPropertyDescriptor() та Object.defineProperty().

Копіюються властивості, що мають за ключі як String, так і Symbol.

В разі помилки (наприклад, якщо властивість недоступна для запису) викидається TypeError, а об'єкт target залишається модифікованим, якщо якісь властивості були вже додані до виникнення помилки.

Примітка: Object.assign() не викидає помилок на таких донорах, як null чи undefined.

Приклади

Клонування об'єкта

const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

Застереження щодо глибинного клонування

Для глибокого клонування необхідно використовувати альтернативи штибу structuredClone(), оскільки Object.assign() копіює значення властивостей.

Якщо значення в донорі містить посилання на об'єкт, Object.assign() скопіює лише це посилання.

const obj1 = { a: 0, b: { c: 0 } };
const obj2 = Object.assign({}, obj1);
console.log(obj2); // { a: 0, b: { c: 0 } }
obj1.a = 1;
console.log(obj1); // { a: 1, b: { c: 0 } }
console.log(obj2); // { a: 0, b: { c: 0 } }
obj2.a = 2;
console.log(obj1); // { a: 1, b: { c: 0 } }
console.log(obj2); // { a: 2, b: { c: 0 } }
obj2.b.c = 3;
console.log(obj1); // { a: 1, b: { c: 3 } }
console.log(obj2); // { a: 2, b: { c: 3 } }
// Глибоке клонування
const obj3 = { a: 0, b: { c: 0 } };
const obj4 = structuredClone(obj3);
obj3.a = 4;
obj3.b.c = 4;
console.log(obj4); // { a: 0, b: { c: 0 } }

Злиття об'єктів

const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };

const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, цільовий об'єкт також змінився.

Злиття об'єктів з однаковими властивостями

const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };

const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Властивості перезаписуються іншими об'єктами, які мають аналогічні властивості далі в переліку аргументів.

Копіювання властивостей із символьними ключами

const o1 = { a: 1 };
const o2 = { [Symbol("foo")]: 2 };

const obj = Object.assign({}, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (для порівняння, вада 1207182 у Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]

Неможливо скопіювати властивості в прототипному ланцюжку чи неперелічувані властивості

const obj = Object.create(
  // foo знаходиться в прототипному ланцюжку obj
  { foo: 1 },
  {
    bar: {
      value: 2, // bar не є перелічуваною властивістю
    },
    baz: {
      value: 3,
      enumerable: true, // baz є власною перелічуваною властивістю.
    },
  },
);

const copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }

Примітиви обгортаються в об'єкти

const v1 = "abc";
const v2 = true;
const v3 = 10;
const v4 = Symbol("foo");

const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// Примітиви обгортаються, null та undefined ігноруються.
// Зауважте, що лише рядкові обгортки мають власні перелічувані властивості.
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

Винятки переривають операцію копіювання, що триває

const target = Object.defineProperty({}, "foo", {
  value: 1,
  writable: false,
}); // target.foo — це властивість лише для читання

Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// TypeError: "foo" is read-only
// Виняток викинуто під час присвоєння значення target.foo

console.log(target.bar); // 2, властивості першого донора успішно скопійовано.
console.log(target.foo2); // 3, перша властивість другого донора скопійована успішно.
console.log(target.foo); // 1, тут викинуто виняток.
console.log(target.foo3); // undefined, робота методу "assign" завершилася, foo3 скопійовано не буде.
console.log(target.baz); // undefined, третій донор також копіюватися не буде.

Копіювання методів доступу

const obj = {
  foo: 1,
  get bar() {
    return 2;
  },
};

let copy = Object.assign({}, obj);
console.log(copy);
// { foo: 1, bar: 2 }
// Значення copy.bar дорівнює поверненому значенню гетера obj.bar.

// Ось фінкція присвоєння, яка капіює дескриптори цілком
function completeAssign(target, ...sources) {
  sources.forEach((source) => {
    const descriptors = Object.keys(source).reduce((descriptors, key) => {
      descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
      return descriptors;
    }, {});

    // Як усталено, Object.assign копіює також перелічувані символи
    Object.getOwnPropertySymbols(source).forEach((sym) => {
      const descriptor = Object.getOwnPropertyDescriptor(source, sym);
      if (descriptor.enumerable) {
        descriptors[sym] = descriptor;
      }
    });
    Object.defineProperties(target, descriptors);
  });
  return target;
}

copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }

Специфікації

Сумісність із браузерами

desktop mobile server
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet Deno Node.js
assign
Chrome Full support 45
Edge Full support 12
Firefox Full support 34
Internet Explorer No support No
Opera Full support 32
Safari Full support 9
WebView Android Full support 45
Chrome Android Full support 45
Firefox for Android Full support 34
Opera Android Full support 32
Safari on iOS Full support 9
Samsung Internet Full support 5.0
Deno Full support 1.0
Node.js Full support 4.0.0

Дивіться також