JavaScript面試考點(diǎn)之深拷貝和淺拷貝

1、數(shù)據(jù)類型

說起拷貝那伐,就不得不提起?js?的數(shù)據(jù)類型了踏施,因?yàn)樯羁截惡蜏\拷貝的核心就在于不同的數(shù)據(jù)類型在內(nèi)存中存儲(chǔ)的地方不同石蔗。

JavaScript中存在基本類型和引用類型。其中基本類型數(shù)據(jù)保存在棧內(nèi)存中畅形,棧具有先進(jìn)后出的特點(diǎn)养距;引用類型數(shù)據(jù)保存在堆內(nèi)存中,引用數(shù)據(jù)類型的變量是存放在棧中的日熬,指向的是堆內(nèi)存中實(shí)際對(duì)象的引用棍厌。

首先我們要知道最新的?ECMAScript?標(biāo)準(zhǔn)定義了 8 種數(shù)據(jù)類型,其中 7 種是基本數(shù)據(jù)類型竖席,它們是String耘纱、Number、Boolean毕荐、Null束析、Undefined、Symbol憎亚、BigInt员寇。對(duì)象類型Object第美。

基本類型:

1)字符串(String)什往,字符串是一串表示文本值的字符序列,例如:“不染-何程龍” 第献。

2)數(shù)字(Number),整數(shù)或浮點(diǎn)數(shù)衫樊,例如: 42 或者 3.14159利花。

3)布爾值(Boolean)臀栈,有2個(gè)值分別是:true 和 false挠乳。

4)null , 一個(gè)表明 null 值的特殊關(guān)鍵字黍析。 JavaScript 是大小寫敏感的阐枣,因此 null 與 Null奄抽、NULL或變體完全不同。

5)undefined 宪哩,和 null 一樣是一個(gè)特殊的關(guān)鍵字锁孟,undefined 表示變量未賦值時(shí)的屬性茁瘦。

6)代表(Symbol)( 在 ECMAScript 6 中新添加的類型).甜熔。一種實(shí)例是唯一且不可改變的數(shù)據(jù)類型腔稀。Symbol 函數(shù)棧不能用 new 命令焊虏。Symbol 值作為屬性名時(shí),該屬性是公有屬性不是私有屬性炼团,可以在類的外部訪問瘟芝。但是不會(huì)出現(xiàn)在 for...in 褥琐、for...of的循環(huán)中敌呈,也不會(huì)被 Object.keys() 贩汉、 Object.getOwnPropertyNames()返回匹舞。如果要讀取到一個(gè)對(duì)象的Symbol 屬性赐稽,可以通過 Object.getOwnPropertySymbols() 和Reflect.ownKeys() 取到浑侥。

Symbol.for() 類似單例模式寓落,首先會(huì)在全局搜索被登記的 Symbol 中是否有該字符串參數(shù)作為名稱的 Symbol 值伶选,如果有即返回該 Symbol 值,若沒有則新建并返回一個(gè)以該字符串參數(shù)為名稱的 Symbol 值构资,并登記在全局環(huán)境中供搜索吐绵。

Symbol.keyFor() 返回一個(gè)已登記的 Symbol 類型值的 key 己单,用來檢測(cè)該字符串參數(shù)作為名稱的 Symbol 值是否已被登記耙饰。

7)任意精度的整數(shù) (BigInt)榔幸,可以安全地存儲(chǔ)和操作大整數(shù)削咆,甚至可以超過數(shù)字的安全整數(shù)限制拨齐。

對(duì)象類型Object:


2、深拷貝與淺拷貝

淺拷貝是指創(chuàng)建新的數(shù)據(jù)掏导,將源對(duì)象的屬性拷貝一份趟咆。如果屬性是基本類型值纱,拷貝的是基本類型的值坯汤;如果為引用類型惰聂,拷貝的是內(nèi)存地址搓幌。修改對(duì)象屬性會(huì)影響原對(duì)象鼻种。

常用的淺拷貝方法:

1)展開運(yùn)算符 ...

2)Object.assign():用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象分配到目標(biāo)對(duì)象叉钥。它將返回目標(biāo)對(duì)象投队。

3)concat和slice數(shù)組方法

如果拷貝的對(duì)象中屬性有引用類型值的話息楔,淺拷貝就不能達(dá)到預(yù)期的完全復(fù)制隔離的效果了值依。

深拷貝是開辟了一個(gè)新的棧碟案,兩個(gè)對(duì)象屬性相同价说。將拷貝過程中遇到的引用類型都新開辟一塊地址拷貝對(duì)應(yīng)的數(shù)據(jù),對(duì)應(yīng)兩個(gè)不同的地址缤弦,避免子對(duì)象共享同一份內(nèi)存的問題了碍沐,修改一個(gè)不會(huì)影響另一個(gè)抢韭。

JSON.parse(JSON.stringify()) 將對(duì)象先轉(zhuǎn)成字符串刻恭,再通過JSON.parse將字符串轉(zhuǎn)成對(duì)象鳍贾,此時(shí)對(duì)象中每個(gè)層級(jí)的堆內(nèi)存都是新開辟的骑科。存在的問題:1)不能解決循環(huán)引用的問題咆爽;2)無法拷貝特殊對(duì)象置森,比如:RegExp、BigInt凫海、Date、Set漾稀、Map等崭捍。

3、手寫深拷貝

1)JSON.stringify

var copy_data = JSON.parse(JSON.stringify(origin_data))

實(shí)現(xiàn)一個(gè)功能類似JSON.parse(JSON.stringify())的簡單深拷貝,能對(duì)對(duì)象和數(shù)組進(jìn)行深拷貝:

不能解決循環(huán)引用的問題;無法拷貝特殊對(duì)象昼蛀,比如:RegExp叼旋、BigInt、Date详民、Set沈跨、Map等

2)遞歸方法

3)淺拷貝 + 遞歸

對(duì)于基本數(shù)據(jù)類型,我們直接拷貝即可;對(duì)于引用數(shù)據(jù)類型杀狡,則需要進(jìn)行遞歸拷貝。

我們使用拷貝對(duì)象的構(gòu)造方法創(chuàng)建對(duì)應(yīng)類型的數(shù)據(jù)恭陡。

首先使用Object.prototype.toString.call()來獲取對(duì)象的準(zhǔn)確類型休玩。

獲取到了具體的引用類型后永部,我們可以根據(jù)對(duì)應(yīng)的類型進(jìn)行初始化對(duì)象的操作。通過target.constructor拿到拷貝對(duì)象的構(gòu)造函數(shù)组橄,通過源對(duì)象的構(gòu)造函數(shù)生成的對(duì)象可以保留對(duì)象原型上的數(shù)據(jù),如果使用{}遵班,則原型上的數(shù)據(jù)會(huì)丟失。

1)Boolean愿阐、Number、String辛孵、Date、Error我們可以直接通過構(gòu)造函數(shù)和原始數(shù)據(jù)創(chuàng)建一個(gè)新的對(duì)象冶匹。

2)Object、Map飞蛹、Set我們直接執(zhí)行構(gòu)造函數(shù)返回初始值墓懂,遞歸處理后續(xù)屬性宛徊,因?yàn)樗鼈兊膶傩钥梢员4鎸?duì)象暖呕。

3)Array湾揽、Symbol、RegExp進(jìn)行特殊處理。

整體代碼框架:

主要的函數(shù)

首先我們對(duì)于參數(shù)進(jìn)行判斷其是否為對(duì)象類型,如果是普通類型,直接返回即可磁滚。

這里我們還增加了緩存機(jī)制,為了防止自身的遞歸調(diào)用,陷入死循環(huán)仪芒。我們使用了WeakSet進(jìn)行儲(chǔ)存据沈,因?yàn)槌蓡T都是弱引用猾警,可以被垃圾回收機(jī)制回收崔慧,不容易造成內(nèi)存泄漏;

使用了Object.prototype.toString.call()來獲取拷貝對(duì)象的準(zhǔn)確類型皇钞。根據(jù)不同的類型利用其的構(gòu)造方法創(chuàng)建對(duì)應(yīng)類型的數(shù)據(jù)惩坑。如果是map和set趾痘,通過獨(dú)有的set滥沫、add方法設(shè)置值世分,單獨(dú)處理。

判斷是否為對(duì)象
主函數(shù)

?首先是創(chuàng)建拷貝對(duì)象,我們可以根據(jù)對(duì)應(yīng)的類型進(jìn)行初始化對(duì)象的操作荣恐。

1)通過target.constructor拿到拷貝對(duì)象的構(gòu)造函數(shù),通過源對(duì)象的構(gòu)造函數(shù)生成的對(duì)象可以保留對(duì)象原型上的數(shù)據(jù)

2)Boolean、Number夺溢、String嘉汰、Date持搜、Error我們可以直接通過構(gòu)造函數(shù)和原始數(shù)據(jù)創(chuàng)建一個(gè)新的對(duì)象。

3)Object抛猫、Map峰档、Set我們直接執(zhí)行構(gòu)造函數(shù)返回初始值毅待,遞歸處理后續(xù)屬性刹泄,因?yàn)樗鼈兊膶傩钥梢员4鎸?duì)象盅蝗。

4)Array逞敷、Symbol牛柒、RegExp進(jìn)行特殊處理椭更。

創(chuàng)建拷貝對(duì)象

對(duì)Array缴川、Symbol、RegExp進(jìn)行特殊處理铭污。

淺拷貝:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恋日,一起剝皮案震驚了整個(gè)濱河市膀篮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌岂膳,老刑警劉巖誓竿,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谈截,居然都是意外死亡筷屡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門簸喂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來毙死,“玉大人,你說我怎么就攤上這事喻鳄《筇龋” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵除呵,是天一觀的道長再菊。 經(jīng)常有香客問我,道長竿奏,這世上最難降的妖魔是什么袄简? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮泛啸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘秃症。我一直安慰自己候址,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布种柑。 她就那樣靜靜地躺著岗仑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪聚请。 梳的紋絲不亂的頭發(fā)上荠雕,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音驶赏,去河邊找鬼炸卑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛煤傍,可吹牛的內(nèi)容都是我干的盖文。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚯姆,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼五续!你這毒婦竟也來了洒敏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤疙驾,失蹤者是張志新(化名)和其女友劉穎凶伙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體它碎,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡函荣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了链韭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偏竟。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖敞峭,靈堂內(nèi)的尸體忽然破棺而出踊谋,到底是詐尸還是另有隱情,我是刑警寧澤旋讹,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布殖蚕,位于F島的核電站,受9級(jí)特大地震影響沉迹,放射性物質(zhì)發(fā)生泄漏睦疫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一鞭呕、第九天 我趴在偏房一處隱蔽的房頂上張望蛤育。 院中可真熱鬧,春花似錦葫松、人聲如沸瓦糕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搪搏。三九已至兄墅,卻和暖如春蚊丐,著一層夾襖步出監(jiān)牢的瞬間诈泼,已是汗流浹背膝迎。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工攘须, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留摧扇,地道東北人圣贸。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像扳剿,于是被迫代替她去往敵國和親旁趟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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