Object.assign的理解

Object.assign函數(shù)的使用,使用該函數(shù)我們可以快速的復(fù)制一個(gè)或者多個(gè)對(duì)象到目標(biāo)對(duì)象中,本文內(nèi)容涉及es6,es7相關(guān)的對(duì)象復(fù)制的內(nèi)容骂租,以及一些es5的替代方案的介紹。

函數(shù)原型

首先看一下函數(shù)的定義:
函數(shù)參數(shù)為一個(gè)目標(biāo)對(duì)象(該對(duì)象作為最終的返回值),源對(duì)象(此處可以為任意多個(gè))斑司。通過調(diào)用該函數(shù)可以拷貝所有可被枚舉的自有屬性值到目標(biāo)對(duì)象中。

Object.assign(target, ...sources)
這里我們需要強(qiáng)調(diào)的三點(diǎn)是:

可被枚舉的屬性
自有屬性
string或者Symbol類型是可以被直接分配的
拷貝過程中將調(diào)用源對(duì)象的getter方法,并在target對(duì)象上使用setter方法實(shí)現(xiàn)目標(biāo)對(duì)象的拷貝宿刮。

函數(shù)實(shí)例

這里我們通過幾個(gè)MDN上的例子來介紹一下使用方法:

實(shí)例一

我們參考上面的原型函數(shù)說明即可知道其最開始的o1因?yàn)樵O(shè)置為target互站,則調(diào)用其setter方法設(shè)置了其他對(duì)象的屬性到自身。

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 }, target object itself is changed.

實(shí)例二

我們自定義了一些對(duì)象僵缺,這些對(duì)象有一些包含了不可枚舉的屬性,另外注意使用 Object.defineProperty 初始化的對(duì)象默認(rèn)是不可枚舉的屬性胡桃。對(duì)于可枚舉的對(duì)象我們可以直接使用Object.keys()獲得,或者使用for-in循環(huán)遍歷出來.

對(duì)于不可枚舉的屬性,使用Object.assign的時(shí)候?qū)⒈蛔詣?dòng)忽略磕潮。

var obj = Object.create({ foo: 1 }, { // foo is an inherit property.
  bar: {
    value: 2  // bar is a non-enumerable property.
  },
  baz: {
    value: 3,
    enumerable: true  // baz is an own enumerable property.
  }
});

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

實(shí)例三

對(duì)于只讀的屬性翠胰,當(dāng)分配新的對(duì)象覆蓋他的時(shí)候,將拋出異常:

var target = Object.defineProperty({}, 'foo', {
  value: 1,
  writable: false
}); 

Object.assign(target, { bar: 2 })

//{bar: 2, foo: 1}

Object.assign(target, { foo: 2 })
//Uncaught TypeError: Cannot assign to read only property 'foo' of object '#<Object>'(…)
Polyfill

這里我們簡(jiǎn)單的看下如何實(shí)現(xiàn)es5版本的Object.assign:

實(shí)現(xiàn)步驟:

判斷是否原生支持該函數(shù)自脯,如果不存在的話創(chuàng)建一個(gè)立即執(zhí)行函數(shù)之景,該函數(shù)將創(chuàng)建一個(gè)assign函數(shù)綁定到Object上。
判斷參數(shù)是否正確(目的對(duì)象不能為空膏潮,我們可以直接設(shè)置{}傳遞進(jìn)去,但必須設(shè)置該值)
使用Object在原有的對(duì)象基礎(chǔ)上返回該對(duì)象锻狗,并保存為out
使用for…in循環(huán)遍歷出所有的可枚舉的自有對(duì)象。并復(fù)制給新的目標(biāo)對(duì)象(hasOwnProperty返回非原型鏈上的屬性)
源碼如下:

 if (typeof Object.assign != 'function') {
  (function () {
    Object.assign = function (target) {
     'use strict';
     if (target === undefined || target === null) {
       throw new TypeError('Cannot convert undefined or null to object');
     }
    
     var output = Object(target);
     for (var index = 1; index < arguments.length; index++) {
       var source = arguments[index];
       if (source !== undefined && source !== null) {
         for (var nextKey in source) {
           if (source.hasOwnProperty(nextKey)) {
             output[nextKey] = source[nextKey];
           }
         }
       }
     }
     return output;
    };
})();
}

擴(kuò)展內(nèi)容

1.深度復(fù)制

當(dāng)我們調(diào)用下面的函數(shù)的時(shí)候焕参,由于Object.assign將覆蓋之前的內(nèi)容轻纪,所以并不能完全的做到融合對(duì)象,而是全部替換掉叠纷,所以返回的對(duì)象內(nèi)容將變成最后一個(gè)值;{a: {c: 3} Object.assign({a: {b: 0}}, {a: {b: 1, c: 2}}, {a: {c: 3}});
如何深層次的融合對(duì)象刻帚,比如我們期望的輸出結(jié)果為:

{a:{b:1,c:3}}

這樣我們必須實(shí)現(xiàn)自己的算法來完成深層復(fù)制了,不過github上已經(jīng)有很多好的解決方案,比如deep-merge 通過遞歸的方式逐層的去調(diào)用assign函數(shù)涩嚣。

2.ES2016實(shí)現(xiàn)

在es7中我們使用rest屬性可以捕獲所有剩余的對(duì)象內(nèi)容比如下面的例子(可使用babel-repl頁(yè)面測(cè)試崇众,瀏覽器一般尚未支持):

let { fname, lname, ...rest } = { fname: "Hemanth", lname: "HM", location: "Earth", type: "Human" };
fname; //"Hemanth"
lname; //"HM"
rest; // {location: "Earth", type: "Human"}

這樣我們就可以使用該特性來實(shí)現(xiàn)assign函數(shù)

let oldObj1={a:"a",b:{b1:"b1"}}
let oldObj2={a:"a1",b:{b2:"b2"},c:"c"}

let newObject={...oldObj1,...oldObj2};
console.log(newObject)

{"a":"a1","b":{"b2":"b2"},"c":"c"}

不過仍舊只是淺層的替換,并沒有實(shí)現(xiàn)深層次的合并缓艳。

3.注意

如果目標(biāo)對(duì)象與源對(duì)象有同名屬性校摩,則后面的屬性會(huì)覆蓋前面的屬性
如果只有一個(gè)參數(shù),則直接返回該參數(shù)阶淘。即Object.assign(obj) === obj
如果第一個(gè)參數(shù)不是對(duì)象衙吩,而是基本數(shù)據(jù)類型(Null、Undefined除外)溪窒,則會(huì)調(diào)用對(duì)應(yīng)的基本包裝類型
如果第一個(gè)參數(shù)是Null和Undefined坤塞,則會(huì)報(bào)錯(cuò);如果Null和Undefined不是位于第一個(gè)參數(shù)澈蚌,則會(huì)略過該參數(shù)的復(fù)制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末摹芙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子宛瞄,更是在濱河造成了極大的恐慌浮禾,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盈电,居然都是意外死亡蝴簇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門匆帚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熬词,“玉大人,你說我怎么就攤上這事吸重』ナ埃” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵嚎幸,是天一觀的道長(zhǎng)颜矿。 經(jīng)常有香客問我,道長(zhǎng)鞭铆,這世上最難降的妖魔是什么或衡? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮车遂,結(jié)果婚禮上封断,老公的妹妹穿的比我還像新娘。我一直安慰自己舶担,他們只是感情好坡疼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著衣陶,像睡著了一般柄瑰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剪况,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天教沾,我揣著相機(jī)與錄音,去河邊找鬼译断。 笑死授翻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的孙咪。 我是一名探鬼主播堪唐,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼翎蹈!你這毒婦竟也來了淮菠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤荤堪,失蹤者是張志新(化名)和其女友劉穎合陵,沒想到半個(gè)月后枢赔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拥知,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年糠爬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片举庶。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖揩抡,靈堂內(nèi)的尸體忽然破棺而出户侥,到底是詐尸還是另有隱情,我是刑警寧澤峦嗤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布蕊唐,位于F島的核電站,受9級(jí)特大地震影響烁设,放射性物質(zhì)發(fā)生泄漏替梨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一装黑、第九天 我趴在偏房一處隱蔽的房頂上張望副瀑。 院中可真熱鬧,春花似錦恋谭、人聲如沸糠睡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狈孔。三九已至,卻和暖如春材义,著一層夾襖步出監(jiān)牢的瞬間均抽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工其掂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留油挥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓清寇,卻偏偏與公主長(zhǎng)得像喘漏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子华烟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 本文為阮一峰大神的《ECMAScript 6 入門》的個(gè)人版提純翩迈! babel babel負(fù)責(zé)將JS高級(jí)語(yǔ)法轉(zhuǎn)義,...
    Devildi已被占用閱讀 1,970評(píng)論 0 4
  • 1.屬性的簡(jiǎn)潔表示法 允許直接寫入變量和函數(shù) 上面代碼表明盔夜,ES6 允許在對(duì)象之中负饲,直接寫變量堤魁。這時(shí),屬性名為變量...
    雨飛飛雨閱讀 1,130評(píng)論 0 3
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,869評(píng)論 6 13
  • 屬性的簡(jiǎn)潔表示法 ES6允許直接寫入變量和函數(shù)返十,作為對(duì)象的屬性和方法妥泉。這樣的書寫更加簡(jiǎn)潔。 上面代碼表明洞坑,ES6允...
    呼呼哥閱讀 2,906評(píng)論 0 2
  • 沒什么條理迟杂,寫到哪兒算哪兒吧刽沾!主要說說這兩周的事兒,權(quán)當(dāng)一個(gè)記錄排拷。真正體會(huì)到二十歲出頭的年紀(jì)是多么美好侧漓,每一次的經(jīng)...
    何為歡何謂喜閱讀 147評(píng)論 0 0