diff options
Diffstat (limited to 'files/zh-tw/web/javascript/reference/global_objects/object/assign/index.html')
-rw-r--r-- | files/zh-tw/web/javascript/reference/global_objects/object/assign/index.html | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/files/zh-tw/web/javascript/reference/global_objects/object/assign/index.html b/files/zh-tw/web/javascript/reference/global_objects/object/assign/index.html new file mode 100644 index 0000000000..f4dfca5af7 --- /dev/null +++ b/files/zh-tw/web/javascript/reference/global_objects/object/assign/index.html @@ -0,0 +1,249 @@ +--- +title: Object.assign() +slug: Web/JavaScript/Reference/Global_Objects/Object/assign +translation_of: Web/JavaScript/Reference/Global_Objects/Object/assign +--- +<div>{{JSRef}}</div> + +<div><strong><code>Object.assign()</code></strong>被用來複製一個或多個物件自身所有可數的屬性到另一個目標物件。回傳的值為該目標物件。</div> + +<h2 id="語法">語法</h2> + +<pre class="syntaxbox notranslate">Object.assign(<var>target</var>, ...<var>sources</var>)</pre> + +<h3 id="參數">參數</h3> + +<dl> + <dt><code>target</code></dt> + <dd>目標物件</dd> + <dt><code>sources</code></dt> + <dd>來源物件</dd> +</dl> + +<h3 id="回傳值">回傳值</h3> + +<p> 合併目標物件及(多個)來源物件所得到的最終物件。</p> + +<h2 id="說明">說明</h2> + +<p>如果在目標物件裡的屬性名稱(key)和來源物件的屬性名稱相同,將會被覆寫。若來源物件之間又有相同的屬性名稱,則後者會將前者覆寫。</p> + +<p><code>Object.assign()</code>只會從來源物件將自身可列舉的屬性複製到目標物件。此函式方法(method) 使用來源物件的<code>[[Get]]</code>事件和目標物件的<code>[[Set]]</code>事件,使它將會執行getters和setters。因此,這邊的指派(<em>assigns</em>)屬性不只是複製或定義新屬性。若在合併包含getters的來源物件時,這個事件可能就不適合用來合併屬性。至於複製屬性的定義(包含其可列舉性)到各屬性,反倒是會用到 {{jsxref("Object.getOwnPropertyDescriptor()")}} 和 {{jsxref("Object.defineProperty()")}} 。</p> + +<p>{{jsxref("String")}} 和 {{jsxref("Symbol")}} 類型的屬性都會被複製。</p> + +<p>若發生錯誤,例如: 當一個屬性不可被寫入時,將會引發 {{jsxref("TypeError")}} 的錯誤,且目標物件剩餘的屬性將不會改變。</p> + +<p>注意: <code>Object.assign()</code> 不會在來源物件屬性的值為{{jsxref("null")}} 或 {{jsxref("undefined")}} 的時候拋出錯誤。</p> + +<h2 id="範例">範例</h2> + +<h3 id="複製物件">複製物件</h3> + +<pre class="brush: js notranslate">var obj = { a: 1 }; +var copy = Object.assign({}, obj); +console.log(copy); // { a: 1 } +</pre> + +<h3 id="Deep_Clone" name="Deep_Clone">警告:非深層複製</h3> + +<p>深層複製(deep clone)需要使用其他的替代方案,因為 <code>Object.assign()</code> 僅複製屬性值。若來源物件的值參照到一個子物件,它只會複製該子物件的參照。</p> + +<pre class="brush: js notranslate">function test() { + let a = { b: {c:4} , d: { e: {f:1}} } + let g = Object.assign({},a) // 淺層 + let h = JSON.parse(JSON.stringify(a)); // 深層 + console.log(g.d) // { e: { f: 1 } } + g.d.e = 32 + console.log('g.d.e set to 32.') // g.d.e set to 32. + console.log(g) // { b: { c: 4 }, d: { e: 32 } } + console.log(a) // { b: { c: 4 }, d: { e: 32 } } + console.log(h) // { b: { c: 4 }, d: { e: { f: 1 } } } + h.d.e = 54 + console.log('h.d.e set to 54.') // h.d.e set to 54. + console.log(g) // { b: { c: 4 }, d: { e: 32 } } + console.log(a) // { b: { c: 4 }, d: { e: 32 } } + console.log(h) // { b: { c: 4 }, d: { e: 54 } } +} +test(); +</pre> + +<h3 id="合併物件">合併物件</h3> + +<pre class="brush: js notranslate">var o1 = { a: 1 }; +var o2 = { b: 2 }; +var o3 = { c: 3 }; + +var obj = Object.assign(o1, o2, o3); +console.log(obj); // { a: 1, b: 2, c: 3 } +console.log(o1); // { a: 1, b: 2, c: 3 }, 目標物件本身也被改變。</pre> + +<h3 id="有相同屬性時合併物件">有相同屬性時合併物件</h3> + +<pre class="brush: js notranslate">var o1 = { a: 1, b: 1, c: 1 }; +var o2 = { b: 2, c: 2 }; +var o3 = { c: 3 }; + +var obj = Object.assign({}, o1, o2, o3); +console.log(obj); // { a: 1, b: 2, c: 3 },屬性c為o3.c的值,最後一個出現的屬性c。</pre> + +<p>所有的屬性會被後方相同屬性名稱的值覆寫。</p> + +<h3 id="複製_Symbol_型別的屬性">複製 Symbol 型別的屬性</h3> + +<pre class="brush: js notranslate">var o1 = { a: 1 }; +var o2 = { [Symbol('foo')]: 2 }; + +var obj = Object.assign({}, o1, o2); +console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox) +Object.getOwnPropertySymbols(obj); // [Symbol(foo)]非不在 +</pre> + +<h3 id="在屬性鏈中的不可列舉屬性不會被複製">在屬性鏈中的不可列舉屬性不會被複製</h3> + +<pre class="brush: js notranslate">var obj = Object.create({ foo: 1 }, { // foo 是 obj 的屬性鏈。 + bar: { + value: 2 // bar 是不可列舉的屬性,因為enumerable預設為false。 + }, + baz: { + value: 3, + enumerable: true // baz 是自身可列舉的屬性。 + } +}); + +var copy = Object.assign({}, obj); +console.log(copy); // { baz: 3 } +</pre> + +<h3 id="原始型別會被包成物件">原始型別會被包成物件</h3> + +<pre class="brush: js notranslate">var v1 = 'abc'; +var v2 = true; +var v3 = 10; +var v4 = Symbol('foo'); + +var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); +// 原始型別會被打包,null和undefined則會被忽略。 +// 注意: 只有打包成物件的字串是可列舉的,即可被複製的。 +console.log(obj); // { "0": "a", "1": "b", "2": "c" } +</pre> + +<h3 id="任何異常將會中斷正進行的複製程序">任何異常將會中斷正進行的複製程序</h3> + +<pre class="brush: js notranslate">var target = Object.defineProperty({}, 'foo', { + value: 1, + writable: false +}); // target.foo 是 read-only (唯讀)屬性 + +Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 }); +// TypeError: "foo" 是 read-only +// 在指派值給 target.foo 時,異常(Exception)會被拋出。 + +console.log(target.bar); // 2, 第一個來源物件複製成功。 +console.log(target.foo2); // 3, 第二個來源物件的第一個屬性複製成功。 +console.log(target.foo); // 1, 異常在這裡拋出。 +console.log(target.foo3); // undefined, 複製程式已中斷,複製失敗。 +console.log(target.baz); // undefined, 第三個來源物件也不會被複製。 +</pre> + +<h3 id="複製的存取程序">複製的存取程序</h3> + +<pre class="brush: js notranslate">var obj = { + foo: 1, + get bar() { + return 2; + } +}; + +var copy = Object.assign({}, obj); +console.log(copy); +// { foo: 1, bar: 2 }, copy.bar的值,是obj.bar的getter回傳的值。 + +// 這個函式用來複製完整的描述內容。 +function completeAssign(target, ...sources) { + sources.forEach(source => { + let descriptors = Object.keys(source).reduce((descriptors, key) => { + descriptors[key] = Object.getOwnPropertyDescriptor(source, key); + return descriptors; + }, {}); + // Object.assign 預設會複製可列舉的Symbols。 + Object.getOwnPropertySymbols(source).forEach(sym => { + let descriptor = Object.getOwnPropertyDescriptor(source, sym); + if (descriptor.enumerable) { + descriptors[sym] = descriptor; + } + }); + Object.defineProperties(target, descriptors); + }); + return target; +} + +var copy = completeAssign({}, obj); +console.log(copy); +// { foo:1, get bar() { return 2 } } +</pre> + +<h2 id="Polyfill">Polyfill</h2> + +<p>{{Glossary("Polyfill","polyfill")}} 不支援Symbol屬性,因為ES5沒有Symbol型別。</p> + +<pre class="brush: js notranslate">if (typeof Object.assign != 'function') { + Object.assign = function (target, varArgs) { // .length of function is 2 + 'use strict'; + if (target == null) { // TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource != null) { // Skip over if undefined or null + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + }; +} +</pre> + +<h2 id="規格">規格</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-object.assign', 'Object.assign')}}</td> + <td>{{Spec2('ES6')}}</td> + <td>Initial definition.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-object.assign', 'Object.assign')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="瀏覽器相容性">瀏覽器相容性</h2> + +<div>{{Compat("javascript.builtins.Object.assign")}}</div> + +<div id="compat-desktop"></div> + +<h2 id="參閱">參閱</h2> + +<ul> + <li>{{jsxref("Object.defineProperties()")}}</li> + <li><a href="/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties">Enumerability and ownership of properties</a></li> +</ul> |