1. 程式人生 > >深度克隆詳解以及實現

深度克隆詳解以及實現

深度克隆詳解:

拷貝陣列/物件沒有生成新的資料,而是複製了一份引用

 

拷貝資料分為兩種型別:

1、基本資料型別:拷貝後會生成一份新的資料,修改拷貝以後的資料不會影響原資料(沒有深淺拷貝之說)

2、物件/陣列:拷貝後不會生成新的資料,而拷貝的是引用,修改拷貝以後的資料影響原來的資料(有深淺拷貝之說)

注意:影響原資料的是淺拷貝

拷貝資料的方法:

1、直接賦值給一個變數(淺拷貝)

       let  obj={username:"kebi",age:18};

        let   obj1=obj;

       修改obj1的資料會影響obj的資料,所以是淺拷貝

2、Object.assign()(淺拷貝)

      let   obj2=Object.assign(obj);

      將源物件的屬性賦值到目標物件上,此時obj2就有obj中的屬性,修改obj2會影響原來的資料

3、Array.prototype.concat()(淺拷貝)

     let  arr=[1,2,3,4,{username:"kebi",age:18}];

     let  arr1=arr.concat()  // concat是連線陣列,如果不傳參,則表示複製原陣列的資料到目標陣列中

    注意:使用此方法時,陣列中的基本資料型別的資料照樣是生成一份新資料拷貝到新陣列中,所以修改新陣列的基本資料型別的資料不會影響原陣列,如果修改陣列中的物件,同樣拷貝的是一份物件的引用到新陣列中,所以修改新陣列的物件會直接影響原來陣列的物件資料。這跟直接賦值有一定的區別

4、Array.prototype.slice()(淺拷貝)

      let  arr2=arr.slice();  //slice是擷取陣列或者字串,不傳參表示預設全部

5、Json.parse(Json.Stringfy())(深拷貝)

      let arr3=JSON.parse(JSON.stringify(arr));

      //先把原陣列轉換為json字串,變為基本資料型別,完全生成一份新資料,然後把新資料轉換為js原陣列,就利用了這一點,實現了深拷貝

拷貝的資料裡不能有函式,處理不了,淺拷貝,拷貝的是引用,修改拷貝以後的資料會影響原資料,深拷貝(深度克隆),拷貝時生成新資料,修改不會影響原資料

 

下面是實現深度克隆的方法:

// 實現深度克隆----物件/陣列
    function checkedType(target) {
        return Object.prototype.toString.call(target).slice(8,-1); //返回檢測的資料型別
    }
    function clone(target) {
        //判斷拷貝的資料型別
        //初始化變數result 成為最終克隆的資料
        let result,targetType=checkedType(target);
        if(targetType === 'Object'){
            result = {}
        }else if(targetType === 'Array'){
            result = []
        }else{
            return target;
        }
        //遍歷目標資料
        for(let i in target){
            //獲取遍歷資料結構的每一項值
            let value = target[i];
            //判斷目標結構裡的每一項值是否存在物件/陣列
            if(checkedType(value) === 'Object' || checkedType(value) === 'Array'){
                //繼續遍歷獲取到的value值
               result[i]=clone(value);
            }else{ //獲取到的value值是基本的資料型別或者是函式
                result[i]=value;
            }
        }
        return result;
    }
    let arr=[1,2,{username:'kebi',age:18}];
    let arr1=clone(arr);
    console.log(arr1);   
    arr1[2].username='gmx';
    console.log(arr,arr1);

總結:

    檢測資料型別方法:typeof、呼叫物件原型的toString方法,利用call的特點實現獲取資料型別。

  for   in   遍歷物件:列舉物件時,輸出的是屬性名,列舉陣列時,輸出的是陣列下標。