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
залишається модифікованим, якщо якісь властивості були вже додані до виникнення помилки.
[!NOTE]
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 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
assign
|
Chrome Full support 45 | Edge Full support 12 | Firefox Full support 34 | Internet Explorer No support Ні | 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 |