> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/val/obj/extend/object.assign.md).

# Object.assign()

[JS](/web/js.md) ⟩ [value](/web/js/val.md) ⟩ [object](/web/js/val/obj.md) ⟩ [extend](/web/js/val/obj/extend.md) ⟩ Object.assign()&#x20;

{% hint style="success" %}

* <mark style="color:yellow;">**copies**</mark> [**all enumerable own property**](/web/js/val/obj/prop/enumerate.md) <mark style="color:yellow;">**values**</mark> from <mark style="color:yellow;">**sources**</mark> to a <mark style="color:orange;">**target**</mark> (with [get/set](/web/js/val/obj/prop/internal.md)).
* and <mark style="color:yellow;">**returns**</mark> the modified <mark style="color:orange;">**target**</mark>.

```javascript
Object.assign(target, source1, source2, ...)  // overwrite target with sources

// similar to 
{...target, ...source1, ...source2}
```

{% endhint %}

{% hint style="danger" %}
☢️ <mark style="color:yellow;">**Alert**</mark>：

* [Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) copies property <mark style="color:yellow;">**values**</mark> (with [get/set](/web/js/val/obj/prop/internal.md)), <mark style="color:red;">**not**</mark> their [**attributes**](/web/js/val/obj/prop/attr.md):exclamation:
* if a <mark style="color:yellow;">**source**</mark> has a <mark style="color:red;">**getter**</mark> or the <mark style="color:yellow;">**target**</mark> has a <mark style="color:red;">**setter**</mark>, they will be <mark style="color:red;">**invoked**</mark>❗️, <mark style="color:red;">**not copied**</mark>❗️  👉 [⛔️ Object.assign causing TypeError](/web/js/val/obj/extend/object.assign/object.assign-causing-typeerror.md)
* use [obj.mergeWith()](/web/js/val/builtin/object/ext/merge-with.md) instead if we want to <mark style="color:yellow;">**copy**</mark> [**accessors**](/web/js/val/obj/prop/getter-setter.md).
  {% endhint %}

{% tabs %}
{% tab title="🧨 雷區" %}
{% hint style="danger" %} <mark style="color:purple;">**Object.assign()**</mark>&#x20;

* <mark style="color:red;">**only**</mark>**&#x20;**<mark style="color:yellow;">**copies**</mark> the <mark style="color:yellow;">**values**</mark> of <mark style="color:green;">**enumerable**</mark> **properties**, <mark style="color:red;">**not**</mark> their [**attributes**](/web/js/val/obj/prop/attr.md):exclamation:
* if one of the **source objects** has an <mark style="color:red;">**accessor**</mark>**&#x20;**<mark style="color:yellow;">**property**</mark>, it is the <mark style="color:red;">**value**</mark>**&#x20;**<mark style="color:yellow;">**returned by the**</mark>**&#x20;**<mark style="color:red;">**getter**</mark> that is <mark style="color:yellow;">**copied**</mark> to the **target object**, <mark style="color:red;">**not**</mark>**&#x20;**<mark style="color:yellow;">**the**</mark>**&#x20;**<mark style="color:red;">**getter**</mark>**&#x20;**<mark style="color:yellow;">**itself**</mark>:exclamation:
  {% endhint %}

{% hint style="danger" %}
❓ 問題： [⛔️ Object.assign causing TypeError](/web/js/val/obj/extend/object.assign/object.assign-causing-typeerror.md)\
💊 解藥： [.assignDescriptors()](/web/js/val/obj/extend/mixin/.assigndescriptors.md)
{% endhint %}

{% hint style="danger" %}
☢️ <mark style="color:yellow;">**Alert**</mark>：

<mark style="color:red;">**Don't**</mark> use [Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) with <mark style="color:yellow;">**sources**</mark> that have <mark style="color:red;">**getters**</mark>, the <mark style="color:orange;">**inner states**</mark> of the sources <mark style="color:red;">**may change**</mark>❗❗❗ 👉 [.assignDescriptors()](/web/js/val/obj/extend/mixin/.assigndescriptors.md)
{% endhint %}
{% endtab %}

{% tab title="⭐️ 重點" %}
{% hint style="info" %}
assigning sources to target (:point\_right: [#fan-li](#fan-li "mention"))
{% endhint %}

<table><thead><tr><th width="183.66666666666666">source property</th><th width="159">target property</th><th>result</th></tr></thead><tbody><tr><td>any</td><td>getter</td><td><mark style="color:red;"><strong>TypeError</strong></mark></td></tr><tr><td>setter (only)</td><td>data</td><td>value of <a href="/web/js/val/prim/undefined.md"><strong>undefined</strong></a> is copied</td></tr><tr><td>non-configurable</td><td>(new) data</td><td>configurable/writable/enumerable <mark style="color:yellow;"><strong>all true</strong></mark></td></tr></tbody></table>
{% endtab %}

{% tab title="🔴 主題" %}

* [⛔️ Object.assign causing TypeError](/web/js/val/obj/extend/object.assign/object.assign-causing-typeerror.md)
* [❗️Object.assign copies with getter/setter](/web/js/val/obj/extend/object.assign/copy-with-getter-setter.md)
* [mergeWithoutOverride()](/web/js/val/obj/extend/mixin/mergewithoutoverride.md)
* [.assignDescriptors()](/web/js/val/obj/extend/mixin/.assigndescriptors.md)
  {% endtab %}

{% tab title="👥 相關" %}

* compare with [obj.mergeWith()](/web/js/val/builtin/object/ext/merge-with.md).
* is used for [mixin](/web/js/val/obj/extend/mixin.md).
* [mergeWithoutOverride()](/web/js/val/obj/extend/mixin/mergewithoutoverride.md) keeps old values.
* [.assignDescriptors()](/web/js/val/obj/extend/mixin/.assigndescriptors.md) copies descriptors instead of values.
* [spread operator (...)](/web/js/grammar/op/spread.md) can be used instead to assign default values.
* see [attribute](/web/js/val/obj/prop/attr.md) for <mark style="color:red;">**enumerable**</mark> properties.
* uses [\[\[Get\]\]](/web/js/val/obj/prop/internal.md) on the **source** object and [\[\[Set\]\]](/web/js/val/obj/prop/internal.md) on the **target** object and invokes [getter/setter](/web/js/val/class/member/getter-setter.md) to perform the task.&#x20;
  {% endtab %}

{% tab title="💈範例" %}

* <mark style="color:yellow;">**assign default values**</mark> ([replit](https://replit.com/@pegasusroe/assign-default-values#index.js))

```javascript
// default values
const defaults = {x: 0, y: 0, z: 0};

// ❌ wrong way:
// -------------------------------------------------------------------
const p = {x: 1};
Object.assign(p, defaults);    // overwrites p with defaults ❌

// ✅ right way
// -------------------------------------------------------------------
let q = {x: 2};

// 1. create new object  2. copy defaults  3. overwrite defaults with q
// ╰───────────── ↓ ─╯   ╰ ↓ ────────────╯  ╰─────────────────────────╯
q = Object.assign({}, defaults, q);    // <─────┘

// ⭐ use ... spread operator
let r = {x: 3};
r = {...defaults, ...r};

p    // { x: 0, y: 0, z: 0 }  <-- ❌ p been overwritten
q    // { x: 2, y: 0, z: 0 }  <-- ✅ q overwrites defaults
r    // { x: 3, y: 0, z: 0 }  <-- ⭐ excellent!
```

* replit ⟩ [Object.assign()](https://replit.com/@pegasusroe/Objectassign#index.js), require ⟩ [Object extension](/web/js/val/builtin/object/ext.md)

```javascript
// ⭐ import
const _Object = require('./ext/Object_ext.js');    // extend Object.prototype
// ---------------------------------------------------------------------------

// ⭐ Object.assign(target, ...sources)
// ----------------------------------------------
// • only copies own enumerable properties
//
// case  source        target
// ----------------------------------------------
// • 1:  data       -> getter        // ⛔ [TypeError]
// • 2:  setter     -> getter        // ⛔ [TypeError]
// • 3:  setter     -> data          // ✅ OK (`undefined` is copied)
// • 4:  non-config -> configurable  // ✅ writable/enumerable/configurable all true by default

// ⭐ targets
const t1 = {
    get age() { return 18 },    // getter (accessor property)
};

const t2 = { age: 18 };         // data property
const t3 = {};                  // empty object

// ⭐ sources

// s1: source with setter (only) property
const s1 = {
    set age(v) {},              // setter (only)
}

// s2: source with non-configurable (enumerable) property
const s2 = {};

// define `s2.x`: own enumerable (data) property
s2.defineProperty('x', {
    value: 1, enumerable: true  // non-configurable by default
});    

// ⭐ log
;[
    
    // • 1: data -> getter
    `t1.assign({age: 6})`,    // ⛔ [TypeError] 
    // Cannot set property 'age' of #<Object> which has only a getter

    // • 2: setter -> getter
    `t1.assign(s1)`,          // ⛔ [TypeError] 
    // Cannot set property 'age' of #<Object> which has only a getter

    // • 3: setter -> data
    `t2.assign(s1)`,          // ✅ { age: undefined }

    // • 4: non-configurable -> configurable/writable/enumerable (new) property
    `t3.assign(s2)`,          // ✅ { x: 1 }
    `t3.propertyDescriptor('x')`,
    // { value: 1, writable: true, enumerable: true, configurable: true }
    
    
].forEach(exprStr => {
    try { log(eval(exprStr)) } catch(e) { logError(e) }
});

// log error
function logError(e) {
    log(`⛔ [${e.constructor.name}]`, e.message);
}
```

{% endtab %}

{% tab title="📗 參考" %}

* [ ] [(2020) JavaScript: The Definitive Guide](/web/master/ref/javascript-the-definitive-guide.md) ⭐️
  * [ ] 6.7 Extending Objects,&#x20;
  * [ ] 14.1 Property Attributes
* [ ] DZone ⟩ [Simplifying the Object.assign Method in JavaScript](https://dzone.com/articles/simplifying-objectassign-method-in-javascript)
* [ ] CodeProject ⟩ [The Object.assign() Method In JavaScript](https://www.codeproject.com/Tips/5293257/The-Object-assign-Method-In-JavaScript)
  {% endtab %}

{% tab title="📘 手冊" %}

* [Object.assign()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
  {% endtab %}
  {% endtabs %}
