前端面試必問之深拷貝淺拷貝

深拷貝械巡、淺拷貝是前端面試的高頻題目乳怎,要想知道它們的區(qū)別我們需要先搞懂它們的定義。

淺拷貝:

創(chuàng)建一個(gè)新對(duì)象察滑,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝打厘。如果屬性是基本類型,拷貝的就是基本類型的值贺辰,如果屬性是引用類型户盯,拷貝的就是內(nèi)存地址 ,所以如果其中一個(gè)對(duì)象改變了這個(gè)地址饲化,就會(huì)影響到另一個(gè)對(duì)象莽鸭。

深拷貝:

將一個(gè)對(duì)象從內(nèi)存中完整的拷貝一份出來(lái),從堆內(nèi)存中開辟一個(gè)新的區(qū)域存放新對(duì)象,且修改新對(duì)象不會(huì)影響原對(duì)象

淺拷貝很容易理解,可以深入研究一下深拷貝吃靠。

深拷貝

乞丐版

在不使用第三方庫(kù)的情況下硫眨,我們想要深拷貝一個(gè)對(duì)象,用的最多的就是下面這個(gè)方法巢块。

JSON.parse(JSON.stringify());

復(fù)制代碼這種寫法非常簡(jiǎn)單礁阁,而且可以應(yīng)對(duì)大部分的應(yīng)用場(chǎng)景,但是它還是有很大缺陷的族奢,比如拷貝其他引用類型姥闭、拷貝函數(shù)、循環(huán)引用等情況歹鱼。

顯然泣栈,面試時(shí)你只說(shuō)出這樣的方法是一定不會(huì)合格的。

接下來(lái)弥姻,我們一起來(lái)手動(dòng)實(shí)現(xiàn)一個(gè)深拷貝方法南片。

基礎(chǔ)版

如果是淺拷貝的話,我們可以很容易寫出下面的代碼:

function clone(target) {
    let cloneTarget = {};
    for (const key in target) {
        cloneTarget[key] = target[key];
    }
    return cloneTarget;
};

創(chuàng)建一個(gè)新的對(duì)象庭敦,遍歷需要克隆的對(duì)象疼进,將需要克隆對(duì)象的屬性依次添加到新對(duì)象上,返回新對(duì)象秧廉。

如果是深拷貝的話伞广,考慮到我們要拷貝的對(duì)象是不知道有多少層深度的拣帽,我們可以用遞歸來(lái)解決問題,稍微改寫上面的代碼:

  • 如果是原始類型嚼锄,無(wú)需繼續(xù)拷貝减拭,直接返回
  • 如果是引用類型,創(chuàng)建一個(gè)新的對(duì)象区丑,遍歷需要克隆的對(duì)象拧粪,將需要克隆對(duì)象的屬性執(zhí)行深拷貝后依次添加到新對(duì)象上。

很容易理解沧侥,如果有更深層次的對(duì)象可以繼續(xù)遞歸直到屬性為原始類型可霎,這樣我們就完成了一個(gè)最簡(jiǎn)單的深拷貝:

function clone(target) {
    if (typeof target === 'object') {
        let cloneTarget = {};
        for (const key in target) {
            cloneTarget[key] = clone(target[key]);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

這是一個(gè)最基礎(chǔ)版本的深拷貝,這段代碼可以讓你向面試官展示你可以用遞歸解決問題宴杀,但是顯然癣朗,他還有非常多的缺陷,比如旺罢,還沒有考慮數(shù)組旷余。

考慮數(shù)組

在上面的版本中,我們的初始化結(jié)果只考慮了普通的object扁达,下面我們只需要把初始化代碼稍微一變荣暮,就可以兼容數(shù)組了:

module.exports = function clone(target) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        for (const key in target) {
            cloneTarget[key] = clone(target[key]);
        }
        return cloneTarget;
    } else {
        return target;
    }
};

循環(huán)引用

對(duì)象存在循環(huán)引用的情況,即對(duì)象的屬性間接或直接的引用了自身的情況:

解決循環(huán)引用問題罩驻,我們可以額外開辟一個(gè)存儲(chǔ)空間穗酥,來(lái)存儲(chǔ)當(dāng)前對(duì)象和拷貝對(duì)象的對(duì)應(yīng)關(guān)系,當(dāng)需要拷貝當(dāng)前對(duì)象時(shí)惠遏,先去存儲(chǔ)空間中找砾跃,有沒有拷貝過(guò)這個(gè)對(duì)象,如果有的話直接返回节吮,如果沒有的話繼續(xù)拷貝抽高,這樣就巧妙化解的循環(huán)引用的問題。

這個(gè)存儲(chǔ)空間透绩,需要可以存儲(chǔ)key-value形式的數(shù)據(jù)翘骂,且key可以是一個(gè)引用類型,我們可以選擇Map這種數(shù)據(jù)結(jié)構(gòu):

  • 檢查map中有無(wú)克隆過(guò)的對(duì)象
  • 有 - 直接返回
  • 沒有 - 將當(dāng)前對(duì)象作為key帚豪,克隆對(duì)象作為value進(jìn)行存儲(chǔ)
  • 繼續(xù)克隆
function clone(target, map = new Map()) {
    if (typeof target === 'object') {
        let cloneTarget = Array.isArray(target) ? [] : {};
        if (map.get(target)) {
            return map.get(target);
        }
        map.set(target, cloneTarget);
        for (const key in target) {
            cloneTarget[key] = clone(target[key], map);
        }
        return cloneTarget;
    } else {
        return target;
    }
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碳竟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狸臣,更是在濱河造成了極大的恐慌莹桅,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烛亦,死亡現(xiàn)場(chǎng)離奇詭異诈泼,居然都是意外死亡懂拾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門铐达,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)岖赋,“玉大人,你說(shuō)我怎么就攤上這事瓮孙〖纸冢” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵衷畦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我知牌,道長(zhǎng)祈争,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任角寸,我火速辦了婚禮菩混,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扁藕。我一直安慰自己沮峡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布亿柑。 她就那樣靜靜地躺著邢疙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪望薄。 梳的紋絲不亂的頭發(fā)上疟游,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音痕支,去河邊找鬼颁虐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卧须,可吹牛的內(nèi)容都是我干的另绩。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼花嘶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼笋籽!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起椭员,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤干签,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拆撼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體容劳,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡喘沿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了竭贩。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚜印。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖留量,靈堂內(nèi)的尸體忽然破棺而出窄赋,到底是詐尸還是另有隱情,我是刑警寧澤楼熄,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布忆绰,位于F島的核電站,受9級(jí)特大地震影響可岂,放射性物質(zhì)發(fā)生泄漏错敢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一缕粹、第九天 我趴在偏房一處隱蔽的房頂上張望稚茅。 院中可真熱鬧,春花似錦平斩、人聲如沸亚享。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)欺税。三九已至,卻和暖如春揭璃,著一層夾襖步出監(jiān)牢的瞬間魄衅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工塘辅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晃虫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓扣墩,卻偏偏與公主長(zhǎng)得像哲银,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呻惕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,089評(píng)論 1 32
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學(xué)習(xí)記錄文檔荆责,今天18年5月份再次想寫文章,發(fā)現(xiàn)簡(jiǎn)書還為我保存起的...
    Jenaral閱讀 2,732評(píng)論 2 9
  • 什么是深拷貝亚脆,什么是淺拷貝 說(shuō)到深淺拷貝做院,就不得不提到另外一個(gè)知識(shí)點(diǎn),那就是引用類型和基本類型以及堆和棧的區(qū)別。再...
    jeff_nz閱讀 844評(píng)論 0 0
  • 寫在前面 各類技術(shù)論壇關(guān)于深拷貝的博客有很多,有些寫的也比我好,那為什么我還要堅(jiān)持寫這篇博客呢,之前看到的一篇博客...
    心_c2a2閱讀 21,132評(píng)論 3 18
  • CocoaPods 上手體驗(yàn): 當(dāng)開發(fā)環(huán)境已經(jīng)具備CocoaPods功能键耕,再次引入三方庫(kù)寺滚,只需要在工程目錄文件Po...
    華子小筑閱讀 336評(píng)論 0 2