深拷貝的幾個誤區

  週末賦閒在家,由於太冷了,不想出門,索性宅一天好了。可是閒着沒事作老是很無聊的,正好新的一年想抓一下童鞋同窗的代碼質量,就隨便打開了幾個童鞋寫的代碼。因而故事就展開了。javascript

  團隊大了以後,如何統一團隊代碼風格實際上是一個蠻重要的問題,目前咱們團隊使用lint的方式進行了限制,此次的review能夠說是初見成效,除了很多同窗偷偷摸摸的經過noverify的方式提交代碼之外。不過沒看多久就發現了一段有趣的代碼:java

 

function deepClone(obj, res = {}) {
    const _res = res;
    for(let key in obj) {
        if (obj[key] == obj) {
            continue;
        }

        if (typeof obj[key] === 'object') {
            if(Array.isArray(obj[key])){
                _res[key] = obj[key].slice();
            } else {
                _res[key] = deepClone(obj[key], _res[key]);
            }
        } else {
            _res[key] = obj[key];
        }
    }
    return _res;
}

 

  初看上去就會好奇,爲何不使用lodash現成的深拷貝呢?一看是個h5的項目,推測多是爲了總體包的大小作了取捨,也無可厚非吧。不過仔細看代碼,乍一看好像還挺好,還細心的考慮的數組的狀況,可是再仔細看得時候又以爲好像有什麼地方不對,若是入參是個字符串感情你給別人返回一個空對象麼。。跑了一個case發現果真有點問題:node

 

var c = { a:1 };
var d = new Map();
d.set('a', 1);
var a = {
    a: 1,
    b: true,
    c: ()=>{console.log(123)},
    d: [1,2],
    e: d,
    f: c,    
    g: {} 
}
var b = deepClone(a);

  

  一、雖然正常的處理好像都沒有什麼問題,可是遇到新的數據結構如Map的時候,這種拷貝就會出問題;數組

  二、另外,它只處理了單層循環引用的狀況,多層的時候狀況會更復雜;安全

  三、並且這樣遞歸,層級一深還會有爆棧的隱患,至關的不安全...網絡

  四、雖然它對單獨處理的數組的拷貝,但若是數組的某項的值是一個對象,它這樣的處理依然有問題...數據結構

  因此深拷貝究竟應該怎麼寫呢?google

  本着能google不手寫的原則,查了下網絡,好的寫法沒發現幾個,卻是幾個誤區經有的文章常常會提到且一筆略過:對象

 

  一、JSON.parse(JSON.stringify(obj)) 的實現究竟算不算深拷貝?blog

    固然算,可是這種實現有幾個潛在風險:

      1)它的原理是將可以JSON化的值JSON化,再從新生成一個新的JSON對象。因此它可以實現的基礎是這個值是可以被JSON化的,像諸如function、map、set全是不能JSON化的,一轉就沒了。

      2) 它還有一個風險是在處理循環引用時是會報錯的。這點不少童鞋在實操的時候特別容易忽略,特別是在node端進行端端通訊的時候,曾經一個報錯查半天,真的是血的教訓。

    因此,若是是純JSON的數據的深拷貝且不包含循環引用,是可使用這個方法的

 

  二、遞歸在js中是有風險的

     常見的實現都是基於遞歸的,可是遞歸自己在js的runtime,很容易由於層級過深而致使爆棧。

     而一般的方式則是經過「拍平」樹級結構的對象成一個數組,來進行拷貝。

  

  三、深拷貝的狀況因業務場景的定義會有不一樣  

    有些業務場景須要保持拷貝對象中的值的引用關係不變,而有些卻要改變。另外,js的數據結構發展到今天,須要在拷貝時處理的邊界狀況已經不少了,你須要好好考慮清楚哪些狀況須要怎麼處理。

  

  其實話說回來,仔細看得話,你會發現第一種寫法和jQuery中extend的方式實際上是很像的,一般的狀況也基本能覆蓋了,不過在如今這個語境下,相比比較「安全」的實現深拷貝,仍是建議使用lodash的cloneDeep(相比jQuery和underscore深拷貝大概60行左右的代碼,lodash使用了近幾百行代碼,考慮了各類邊界狀況,也可謂是業界楷模了)

相關文章
相關標籤/搜索