前言
最開始了解到深淺拷貝是因為准備面試,但那個時候因為在學校做的項目比較少需求也比較簡單,所以沒有在項目中遇到這類問題,所以對這個問題就屬於知道這個知識點,看過相關內容,卻沒有自己的總結,也沒有深入的了解。后來在工作中遇到過兩次這樣的問題,第一次遇到后我寫了一篇文章《在vue項目中遇到關於對象的深淺拷貝問題(地址指向)》https://www.cnblogs.com/songForU/p/11187861.html,記錄了需求、錯誤代碼及解決方案,那個時候認為自己的解決方案就是深拷貝;然而第二次遇到問題后,無論我怎么使用那些方案都無法解決問題,也寫了一篇文章記錄了一下解決方案,《javascript數組/對象數組的深淺拷貝問題》https://www.cnblogs.com/songForU/p/11469498.html,但是很遺憾我依舊沒有搞明白之前我認為的“深拷貝”為什么出現了問題,可笑的是依舊沒有去深入了解,只是簡單的記住了解決方案。
直到最近我組長給我一個截圖,上面是關於深淺拷貝的知識點。我看了內容就懵了,為啥我之前認為“深拷貝”方法是淺拷貝,那到底什么是深淺拷貝?截圖內容大致如下:
淺拷貝
拷貝屬性值到新的對象中,如果屬性是對象的話拷貝的是地址,對象屬性指向共同的地址;其中Object.assign()和...可以實現淺拷貝。
深拷貝
拷貝屬性值到新的對象中;兩個對象沒有任何關系;可以通過JSON.parse(JSON.stringify(object))進行大多數的拷貝,;這個方法有一定的局限性,如下:
1、會忽略undefined
2、會忽略symbol
3、不能序列化函數
4、不能解決循環引用的對象
一、淺拷貝
問:什么是淺拷貝?
涉及到深淺拷貝則是關於對象的復制,但是並不是所有的復制操作都叫做淺拷貝。現在我的理解是,我們對引用類型進行復制想要的結果無非是,兩個變量互不影響即可,也就是所謂的深拷貝。當你在進行對象復制的時候,只要保證了復制后的對象和被復制的對象的內存地址是兩個完全不同地址,則便達到了“深拷貝”,可能你這種方法並不適用於所有對象,有局限性罷了,但是確實是達到了效果。
我之前對深淺拷貝產生誤解就是由於自己認為的那些完成了“深拷貝”的方法不適用與所有對象罷了,特別是那些有嵌套對象關系的。
1)Object.assign()、展開運算符...、Array.prototype.slice()、concat等真的不能達到“深拷貝”的效果么?
凡事都有例外,想找到一個普世通用的理論或方法,總那么不盡人意,但總能解決一部分的問題。
像下面這種沒有嵌套關系的對象、數組,即第一層為基本數據類型的,使用上面的幾個方法都可以達到“深拷貝”的效果,去改變復制后的數據不會使原數據同一改變,因為此時兩者的內存地址也是不同的。
let obj = { name:"song", age:1 } let arr = ["1","2","3"];
但是對於復雜的數組,嵌套的對象則不適用,即第一層不是基本數據類型而是引用數據類型;使用上述方法后在改變數據包含的對象則會使原數據一同改變。
let obj = { name:"song", age:1, job:{ price:10, work:"eng" } } let arr = ["1","2",[2,3]]; let arr = ["1","2",{name:"s",age:1}];
當然也不是說,只要是復雜嵌套的對象就一定不能使用上述方法來達到”深拷貝“的效果。如果在開發項目中,你知道數據的結構便可以對數據二次遍歷操作,從而達到"深拷貝"的效果。就比如我之前做的項目中的使用方法。
dataList.map(o => ({...o}));
2)深拷貝
所謂的深拷貝就是會拷貝所有的屬性后,操作任意一個,兩者互不影響,無論是幾層嵌套都能夠各自獨立。
一般來說比較簡單的方法是利用JSON.parse(JSON.stringify(object)),但該方法也存在一些問題,只不過比剛才淺拷貝的幾種方法,解決拷貝問題的通用性更高一些罷了。
當對象里面包含有以下內容,哪怕是一層結構也會有問題。
1、會忽略
undefined2、會忽略
symbol3、不能序列化函數
4、不能解決循環引用的對象
示例如下:
let obj = { name:"song", va:undefined, vb:Symbol('song'), vc:function () {} } console .log(obj); let a = JSON.parse(JSON.stringify(obj)); console.log(a);

3)怎么樣實現一個深拷貝?
(暫未整理)
