基本數據類型的複製很簡單,就是賦值操做,因此深淺拷貝也是針對Object,Array這類引用類型數據。javascript
淺拷貝對於字符串來講,是值的複製,而對於對象來講則是對對象地址的複製;而深拷貝的話,它不只將對象的各個屬性逐個複製出來,還將各個屬性所包含的對象也依次複製出來,至關於在堆區又新開了一塊地存放,主要採起遞歸來實現。css
淺拷貝:java
let originObj={ color:['red','green'], num:5 }; function shallowClone(obj){ let newObj=(obj instanceof Array) ? []:{}; for(let item in obj){ if(obj.hasOwnProperty(item)){ // 避免列舉出原型上的屬性 newObj[item]=obj[item]; } } return newObj; } let cloneObj=shallowClone(originObj);
深拷貝:算法
function deepClone(obj){ let newObj=(obj instanceof Array)? [] : {}; for(let item in obj){ if(obj.hasOwnProperty){ const val=obj[item]; debugger newObj[item]=typeof val==='object' ? deepClone(val) : val; } } return newObj; } let cloneObj2=deepClone(originObj);
其實,這種深拷貝的實現仍是有些問題的,好比日期
,正則對象
沒法複製,還有一個是循環引用
,相似閉包會內存泄露同樣,這樣的對象深拷貝也會陷入一個閉環,直到棧溢出。
爲了解決這個問題,就得先判斷這個對象是否等於原對象。segmentfault
function deepClone(obj){ let tempArr=[]; let newObj=(obj instanceof Array) ? [] : {}; tempArr.push(obj); for(let item in obj){ if(typeof obj[item] === 'object'){ const index=tempArr.indexOf(obj[item]); // 若是已存在,證實引用了相同對象,那麼不管是循環引用仍是重複引用,咱們返回引用就能夠了 if(index>-1){ newObj[item]=tempArr[index]; }else{ newObj[item]=obj[item]; } }else{ newObj[item]=obj[item]; } } return newObj; }
let newObj1=Object.assgin({},originObj); let newObj2={...obj}; // 數組用[...obj]
注:Object.assgin和擴展運算符實現的都是淺拷貝。
這種方法簡單是簡單,不過這個方法有如下缺陷:數組
1.會忽略函數對象以及原型對象,正則會複製成空對象,而日期對象會變成字符串。 2.它會拋棄對象的constructor。也就是深拷貝以後,無論這個對象原來的構造函數是什麼,在深拷貝以後都會變成Object; 3.若是對象中存在循環引用的狀況沒法正確處理。
按需取用吧。閉包
let originObj={fn:function(){console.log(111)}, colors:['red','gree'],reg:/\s/g}; let newObj=JSON.parse(JSON.stringify(originObj));
轉自連接:深刻剖析 JavaScript 的深複製ide
順便安利下underscore,真的挺好用的一個庫: Underscore中文文檔
這個方法其實是一種淺複製 (shallow-copy),全部嵌套的對象和數組都是直接複製引用而並無進行深複製。函數
let originObj={ color:['red','green'], num:5 }; let newObj=_.clone(originObj); newObj.colors.push('grey'); originObj.colors; // ['red','green','grey'];
源碼邏輯很簡單:(固然調用的其餘方法也是underscore的)post
// Create a (shallow-cloned) duplicate of an object. _.clone = function(obj) { if (!_.isObject(obj)) return obj; return _.isArray(obj) ? obj.slice() : _.extend({}, obj); }
這個用法很簡單:
let originObj={ color:['red','green'], num:5 }; let shallowClone=$.extend({},originObj); // 淺拷貝 let deepClone=$.extend(true,{},originObj); // 深拷貝,第一個參數表示是否深度合併對象
lodash深拷貝——這個算是這幾個裏面最完善的方法了,日期
,函數
,正則對象
統統都能複製。
在lodash中關於複製的方法有兩個,分別是_.clone()
和_.cloneDeep()
。其中_.clone(obj, true)
等價於_.cloneDeep(obj)
。
沒引入的能夠點擊上面的文檔連接去直接改動代碼試試看。
另外,查資料過程當中還看到這麼一個詞: 結構化克隆算法
還有這一篇資料也有參考,也寫得比較詳細了: JS的深淺拷貝