Object.assign()方法

Object.assign()方法用于將所有可枚舉的屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象。

語法

Object.assign(target, ...sources)

參數(shù)

target

目標(biāo)對(duì)象。

sources

(多個(gè))源對(duì)象。

返回值

目標(biāo)對(duì)象。

描述

如果目標(biāo)對(duì)象中的屬性具有相同的鍵,則屬性將被源中的屬性覆蓋。后來的源的屬性將類似地覆蓋早先的屬性。

Object.assign方法只會(huì)拷貝源對(duì)象自身的并且可枚舉的屬性到目標(biāo)對(duì)象身上。該方法使用源對(duì)象的 [ [ Get ] ] 和目標(biāo)對(duì)象的 [ [ Set ] ],所以它會(huì)調(diào)用相關(guān) getter 和 setter。因此,它分配屬性而不是復(fù)制或定義新的屬性。如果合并源包含了 getter,那么該方法就不適合將新屬性合并到原型里。假如是拷貝屬性定義到原型里,包括它們的可枚舉性,那么應(yīng)該使用Object.getOwnPropertyDescriptor()Object.defineProperty()。

String類型和Symbol類型的屬性都會(huì)被拷貝。

注意,在屬性拷貝過程中可能會(huì)產(chǎn)生異常,比如目標(biāo)對(duì)象的某個(gè)只讀屬性和源對(duì)象的某個(gè)屬性同名,這時(shí)該方法會(huì)拋出一個(gè)TypeError異常,拷貝過程中斷,已經(jīng)拷貝成功的屬性不會(huì)受到影響,還未拷貝的屬性將不會(huì)再被拷貝。

注意,Object.assign會(huì)跳過那些值為nullundefined的源對(duì)象。

示例

復(fù)制一個(gè) object

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

深度拷貝問題

針對(duì)深度拷貝,需要使用其他方法,因?yàn)镺bject.assign() 拷貝的是屬性值。假如源對(duì)象的屬性值是一個(gè)指向?qū)ο蟮囊?,它也只拷貝那個(gè)引用值。

functiontest(){leta={b:{c:4},d:{e:{f:1}}}letg=Object.assign({},a)leth=JSON.parse(JSON.stringify(a));console.log(g.d)// { e: { f: 1 } }g.d.e=32console.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=54console.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();

合并?objects

varo1={a:1};varo2={b:2};varo3={c:3};varobj=Object.assign(o1,o2,o3);console.log(obj);// { a: 1, b: 2, c: 3 }console.log(o1);// { a: 1, b: 2, c: 3 }, 注意目標(biāo)對(duì)象自身也會(huì)改變。

拷貝 symbol 類型的屬性

varo1={a:1};varo2={[Symbol("foo")]:2};varobj=Object.assign({},o1,o2);console.log(obj);// { a: 1, [Symbol("foo")]: 2 }

繼承屬性和不可枚舉屬性是不能拷貝的

varobj=Object.create({foo:1},{// foo 是個(gè)繼承屬性。bar:{value:2// bar 是個(gè)不可枚舉屬性。},baz:{value:3,enumerable:true// baz 是個(gè)自身可枚舉屬性。}});varcopy=Object.assign({},obj);console.log(copy);// { baz: 3 }

原始類型會(huì)被包裝為 object

varv1="abc";varv2=true;varv3=10;varv4=Symbol("foo")varobj=Object.assign({},v1,null,v2,undefined,v3,v4);// 原始類型會(huì)被包裝,null 和 undefined 會(huì)被忽略。// 注意,只有字符串的包裝對(duì)象才可能有自身可枚舉屬性。console.log(obj);// { "0": "a", "1": "b", "2": "c" }

異常會(huì)打斷接下來的拷貝任務(wù)

vartarget=Object.defineProperty({},"foo",{value:1,writable:false});// target 的 foo 屬性是個(gè)只讀屬性。Object.assign(target,{bar:2},{foo2:3,foo:3,foo3:3},{baz:4});// TypeError: "foo" is read-only// 注意這個(gè)異常是在拷貝第二個(gè)源對(duì)象的第二個(gè)屬性時(shí)發(fā)生的。console.log(target.bar);// 2,說明第一個(gè)源對(duì)象拷貝成功了。console.log(target.foo2);// 3,說明第二個(gè)源對(duì)象的第一個(gè)屬性也拷貝成功了。console.log(target.foo);// 1,只讀屬性不能被覆蓋,所以第二個(gè)源對(duì)象的第二個(gè)屬性拷貝失敗了。console.log(target.foo3);// undefined,異常之后 assign 方法就退出了,第三個(gè)屬性是不會(huì)被拷貝到的。console.log(target.baz);// undefined,第三個(gè)源對(duì)象更是不會(huì)被拷貝到的。

拷貝訪問器(accessor)

varobj={foo:1,getbar(){return2;}};varcopy=Object.assign({},obj);// { foo: 1, bar: 2 }// copy.bar的值來自obj.bar的getter函數(shù)的返回值console.log(copy);// 下面這個(gè)函數(shù)會(huì)拷貝所有自有屬性的屬性描述符functioncompleteAssign(target,...sources){sources.forEach(source=>{letdescriptors=Object.keys(source).reduce((descriptors,key)=>{descriptors[key]=Object.getOwnPropertyDescriptor(source,key);returndescriptors;},{});// Object.assign 默認(rèn)也會(huì)拷貝可枚舉的SymbolsObject.getOwnPropertySymbols(source).forEach(sym=>{letdescriptor=Object.getOwnPropertyDescriptor(source,sym);if(descriptor.enumerable){descriptors[sym]=descriptor;}});Object.defineProperties(target,descriptors);});returntarget;}varcopy=completeAssign({},obj);// { foo:1, get bar() { return 2 } }console.log(copy);

Polyfill

由于 ES5 里壓根就沒有 symbol 這種數(shù)據(jù)類型,所以這個(gè)polyfill也沒必要去支持 symbol 屬性(意思就是說,有 symbol 的環(huán)境一定有原生的Object.assign):

if(typeofObject.assign!='function'){Object.assign=function(target){'use strict';if(target==null){thrownewTypeError('Cannot convert undefined or null to object');}target=Object(target);for(varindex=1;index

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評(píng)論 19 139
  • 一. 字符串的一些擴(kuò)展 for...of遍歷ES6為字符串添加了遍歷器接口,似的字符串可以被for...of循環(huán)遍...
    我不叫奇奇閱讀 452評(píng)論 0 0
  • 《ECMAScript6 入門》阮一峰 讀書筆記 let和constlet聲明的變量?jī)H在塊級(jí)作用域內(nèi)有效,var聲...
    親愛的孟良閱讀 827評(píng)論 1 2
  • 合并多個(gè)對(duì)象 克隆對(duì)象(淺); 為對(duì)象添加多個(gè)方法
    qqqc閱讀 306評(píng)論 0 0
  • 屬性的簡(jiǎn)潔表示法 ES6允許直接寫入變量和函數(shù),作為對(duì)象的屬性和方法。這樣的書寫更加簡(jiǎn)潔。 上面代碼表明,ES6允...
    呼呼哥閱讀 3,024評(píng)論 0 2

友情鏈接更多精彩內(nèi)容