js deep clone 深克隆

首先,值的拷貝,一般有三種方式,因爲基本類型與引用類型在內存中存儲位置和存儲方式的不一樣,致使瞭如下三種概念的衍生:javascript

  • = 賦值:多個指針指向的是同一個堆中的地址,因此相互有影響;
  • 淺拷貝:在堆中從新建立內存,拷貝先後基本數據類型不受影響,但只拷貝一層,沒法拷貝子對象;因此改變淺拷貝獲得的對象中的引用類型時,原始數據會受到影響;例如數組的concat和slice方法;
  • 深拷貝:對子對象也能夠拷貝,拷貝先後兩個對象互不影響,是對對象以及對象的全部子對象進行拷貝;思路就是遞歸調用淺拷貝的邏輯,把全部屬於對象的屬性類型都遍歷賦給另外一個對象便可。徹底的拷貝一個對象,即便嵌套了對象,二者也相互分離,修改一個對象的屬性,也不會影響另外一個。


看下數組結構的拷貝:

var new_arr = JSON.parse( JSON.stringify(arr) );複製代碼

但此法沒法拷貝函數。concat、slice、JSON.stringify 都算是技巧類,能夠根據實際狀況適當使用。java

初步實現一個淺拷貝:

在看開源項目的過程當中,常常會看到相似以下的源碼。for...in循環對象的全部枚舉屬性,而後再使用hasOwnProperty()方法來忽略繼承屬性。
git

const shallowClone = (obj) => {  
    if (typeof obj !== 'object') return
    let newObj = obj instanceof Array ? [] : {}  
    for (let key in obj) {    
        if (obj.hasOwnProperty(key)) {      
            newObj[key] = obj[key]    
        }  
     }
     return newObj
}複製代碼

初步實現一個深拷貝:

const deepClone = (obj) => {  
    if (typeof obj !== 'object') return
    let newObj = obj instanceof Array ? [] : {}  
    for (let key in obj) {    
       if (typeof obj[key] === 'object') {      
         newObj[key] = deepClone(obj[key])    
       } else {      
          newObj[key] = obj[key]    
       }  
     }
     return newObj
}複製代碼

深拷貝會徹底的克隆一個新對象,但由於使用遞歸,性能會不如淺拷貝,在開發中,仍是要根據實際狀況進行選擇。
github


第三方庫的實現

Underscore _.clone()
segmentfault

其實是一種淺複製 (shallow-copy),全部嵌套的對象和數組都是直接複製引用而並無進行深複製。源碼:
數組

// Create a (shallow-cloned) duplicate of an object.
_.clone = function(obj) {
  if (!_.isObject(obj)) return obj;
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};複製代碼

jQuery $.extend()

var x = {
    a: 1,
    b: { f: { g: 1 } },
    c: [ 1, 2, 3 ]
};

var y = $.extend({}, x),          //shallow copy
    z = $.extend(true, {}, x);    //deep copy

y.b.f === x.b.f       // true
z.b.f === x.b.f       // false複製代碼

lodash  _.clone() / _.cloneDeep()

在lodash中關於複製的方法有兩個,分別是_.clone()_.cloneDeep()。其中_.clone(obj, true)等價於_.cloneDeep(obj)
bash

jQuery 沒法正確深複製 JSON 對象之外的對象,而 lodash 花了大量的代碼來實現 ES6 引入的大量新的標準對象。lodash 針對存在環的對象的處理也是很是出色的。所以相較而言,lodash 在深複製上的行爲反饋比前兩個庫好不少。函數


參考源:
post

https://juejin.im/post/59ac1c4ef265da248e75892b
性能

https://segmentfault.com/a/1190000002801042

https://github.com/mqyqingfeng/Blog/issues/32

相關文章
相關標籤/搜索