面試官:如何實現深拷貝

寫在前面

深拷貝應該是前端面試中經常被問到的問題之一,搞定它可以讓我們在面試中如魚得水。那麼什麼是深拷貝呢?它和淺拷貝有什麼區別呢?如何實現一個深拷貝?相信看完這篇文章你就能回答上面的問題了。

一、簡單解釋

我們都知道js的數據類型包括兩種:基本數據類型和引用數據類型。我們今天所說的深拷貝和淺拷貝都只針對引用數據類型,淺拷貝只複製指向某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內存;但深拷貝會創造一個一模一樣的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。紙上得來終覺淺,先來一個例子,藉助例子大家會看的更明白。

var obj = {
    name:'zhang',
    say:function(){
        console.log('hi');
    },
    a:undefined,
    b:{c:'hello'}
}

二、淺拷貝

淺拷貝常用方法:

//方法一:
var newObj = {...obj}
//方法二:
var newObj = Object.assign({},obj)

接下來我們看看淺拷貝有什麼特性:

	var obj2 = {...obj};
    obj.b.c = 'world'
    console.log(obj.b.c);  //world
    console.log(obj2.b.c); //world
    console.log(obj === obj2); //true

從代碼的運行結果我們可以得知,拷貝後的新對象和舊對象還是共享同一塊內存空間。當我們修改新對象的某個屬性時,舊對象的那個屬性也被修改了,顯然這不是我們想要的結果。

三、深拷貝

上面淺拷貝的結果並不是我們想要的,那麼深拷貝會是什麼結果呢?深拷貝有多種方法,在這裏我們只講兩種:

3.1利用JSON.stringfy()和JSON.parse()實現深拷貝

	var obj2 = JSON.parse(JSON.stringify(obj))
    obj2.b.c = 'world'
    console.log(obj.b.c);  //hello
    console.log(obj2.b.c); //world
    console.log(obj === obj2); //false

同樣的代碼,和上面的淺拷貝運行結果完全不一樣。看到這裏是不是覺得深拷貝很簡單啊,一行代碼就實現了。事實並沒有那麼簡單,我們再打印一下拷貝的obj2對象
在這裏插入圖片描述
是的,你沒有看錯,深拷貝後的obj2對象竟然沒有了屬性a和say方法,這有點坑啊!注意: 使用這種方法拷貝對象時,當對象的屬性值是undefined、function、symbol類型時,在轉換過程中會被忽略。而且這種方法也無法實現對RegExp等特殊對象的克隆。所以這種方法還是要謹慎使用。

3.2構造深拷貝函數

  function clone(obj){
        var cloneObj = Array.isArray(obj) ? [] : {};
        if(obj && typeof obj === 'object'){
            for(key in obj){
                if(obj.hasOwnProperty(key)){
                    //如果對象的屬性還是對象  則遞歸調用
                    if(obj[key] && typeof obj[key] === 'object'){
                        cloneObj[key] = clone(obj[key])
                    }else{
                        cloneObj[key] = obj[key]
                    }
                }
            }
        }
        return cloneObj;
    }

代碼應該很好理解,關鍵的一點就是判斷對象的屬性,如果還是對象就遞歸賦值。同樣我們測試一下:

	var obj2 = clone(obj);
    obj2.b.c = 'world'
    console.log(obj.b.c);  
    console.log(obj2.b.c); 
    console.log(obj === obj2); 
    console.log(obj);
    console.log(obj2);

運行結果:
在這裏插入圖片描述
ok,結果沒毛病!

後話

看到這裏大家都能夠回答我們在文章開頭提出的那三個問題了吧。其實深拷貝還有其他方法,比如jquery的extend方法、lodash函數庫的cloneDeep方法等,不過這些方法很少用到,有興趣的同學可以瞭解一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章