

??個人主頁: 鑫寶Code
??熱門專欄: 閑話雜談| 炫酷HTML | JavaScript基礎(chǔ)
???個人格言: "如無必要,勿增實體"
引入
上次講了淺拷貝,這次我們來講深拷貝。有一說一,深拷貝也算是面試時非常常見的題目了。??
深拷貝的作用
首先為什么需要深拷貝,因為淺拷貝無法滿足我們對原始數(shù)據(jù)完整、獨立復制的需求。我們希望修改新對象不會影響原對象。
深淺拷貝的區(qū)別
這里引用
ConardLi
大佬的理解
淺拷貝
創(chuàng)建一個新對象,這個對象有著原始對象屬性值的一份精確拷貝。
- 如果屬性是基本類型,拷貝的就是基本類型的值.
- 如果屬性是引用類型,拷貝的就是內(nèi)存地址
所以如果其中一個對象改變了這個地址,就會影響到另一個對象。

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

深拷貝實現(xiàn)方式
JSON.parse(JSON.stringify())
遙記當年,我當時還是大三的時候,背了一周的面經(jīng)就跑去字節(jié)面試實習生了。面試官就讓我手撕深拷貝。
我當時才20剛出頭,前端面經(jīng)也才抱起來背了不到一周。這種題目我寫的來得?
跟面試官面面相覷了半天,突然靈機一動,JSON.parse(JSON.stringfy())大法一定可以。
我當時非常開心的說出了這個答案, 面試官當時好像有點尬住了,嘴角流露出一股察摸不到的笑容。
但可能由于接受過專業(yè)的訓練,也只在那短短的時間內(nèi)便消失不見。??
介紹
JSON.parse(JSON.stringify())
,首先使用利用JSON.stringify
將對象轉(zhuǎn)成JSON
字符串。 再用JSON.parse
把字符串解析成對象,一去一來,新的對象產(chǎn)生了,而且對象會開辟新的棧,實現(xiàn)深拷貝。
使用例子
const a = {
name: '張三',
score:{
math: 100
}
}
const b = JSON.parse(JSON.stringify(a));
// 改變b中的對象的值
b.score.math = 60;
console.log('a的值',a);
console.log('b的值',b);
/**
* 輸出的結(jié)果如下
* a的值 { name: '張三', score: { math: 100 } }
* b的值 { name: '張三', score: { math: 60 } }
*/
缺點
記個TODO:下次寫文章詳細分析下
JSON.stringify
的缺點。
- 不會拷貝對象上為
undefined
的值 - 不能處理函數(shù)
- 不能處理正則
- 循環(huán)引用會報錯
-
Symol
會丟失等
Lodash的cloneDeep
續(xù)借上文,面試官笑了笑,說
JSON.parse(JSON.stringify())
這個方式有如上幾個缺點,你能不能換個更好的方式將這個問題解決呢?這又一次的讓我陷入了思索,又開始了與面試官的面面相覷??。突然我想起了以前用的Lodash,其中有一個NB的方法。
cloneDeep
,當時我洋洋得意,心想lodash
庫的方法,總不可能還有缺點吧?此時,面試官的表情稍稍有點微妙,我的第六感告訴我,我好像答錯了,不過我認為我回答的沒問題呀。
晌久,面試官嘆了口氣說,我是讓你手撕,手撕懂嗎?
介紹
_.cloneDeep
是lodash
庫提供的深拷貝的方法,非常實用,建議背誦??。
使用例子
import * as _ from "lodash";
const a = {
name: "張三",
score: {
math: 100,
},
};
const b = _.cloneDeep(a);
缺點
暫無,??的lodash庫,??的cloneDeep函數(shù)。
手撕深拷貝
誒,還是得手撕呀,來吧來吧,還是得給面試官露一手的??
基礎(chǔ)版本
多年面試經(jīng)驗告訴我,一般寫出這個版本,幾乎都讓過了,頂多在回答一下循環(huán)引用問題如何解決。一般不太會讓寫一個比較完美的深拷貝的。??
- 首先,我們要拷貝的數(shù)據(jù)類型有兩種,分別是
Array
和Object
- 如果對象里的屬性還是對象,那么采用遞歸對這個對象再進行拷貝
- 如果對象里的屬性不是對象,那么直接返回即可。
代碼如下:
function deepClone(target) {
if (typeof target === "object") {
let cloneTarget = Array.isArray(target) ? [] : {};
for (const key in target) {
cloneTarget[key] = deepClone(target[key]);
}
return cloneTarget;
} else {
return target;
}
}
const a = {
name: "張三",
score: {
math: 100,
},
};
const b = deepClone(a);
/** 輸出的b與a一樣 **/
但是這樣實現(xiàn)會有若干個問題:
- 循環(huán)引用問題無法解決
-
Date
和RegExp
等對象無法拷貝
進階版本
之所以用
weakMap
,是因為weakMap
的鍵是弱引用,可以在任何時刻被回收。如果想了解更清楚進階深拷貝的原理,可以參閱 如何寫出一個驚艷面試官的深拷貝?
function deepClone(target, hash = new WeakMap()) {
if (target === null) return null;
if (typeof target !== "object") return target;
if (target instanceof Date) return new Date(target);
if (target instanceof RegExp) return new RegExp(target);
// 如果hash里有值,立馬返回
if (hash.has(target)) return hash.get(target);
const cloneTarget = Array.isArray(target) ? [] : {};
hash.set(target,cloneTarget);
if (typeof target === "object") {
for (const key in target) {
cloneTarget[key] = deepClone(target[key],hash);
}
return cloneTarget;
} else {
return target;
}
}
const a = {
name: "張三",
score: {
math: 100,
},
date: new Date(),
regex: /^\d{3,4}-\d{5,8}$/,
};
a.child = a;
const b = deepClone(a);
運行結(jié)果如下:

參考資料
如何寫出一個驚艷面試官的深拷貝?
淺拷貝與深拷貝文章來源:http://www.zghlxwxcb.cn/news/detail-839278.html

文章來源地址http://www.zghlxwxcb.cn/news/detail-839278.html
到了這里,關(guān)于【JavaScript】面試手撕深拷貝的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!