1. 程式人生 > 實用技巧 >深淺拷貝 詳解

深淺拷貝 詳解

物件的深淺拷貝

1.淺拷貝的方法

  • =

    • 直接賦值改變其中的一個數組另一個數組也會變

       let arr1=[1,2,3,4]
               let arr2=arr1;
               arr1[0]=9;
               console.log(arr1);//[9, 2, 3, 4]
               console.log(arr2);// [9, 2, 3, 4]

  • assign

    • 利用物件的自帶方法 Object.assign({},obj)

       let obj = {
                   people:{
                      age:20
                   }
              }
              let p 
      = Object.assign({},obj) p.people.age=30; console.log(p.people.age);//30 console.log(obj.people.age);//30

  • {...arr}

    • es6中的陣列解構賦值來拷貝

      let arr = [
                      {
                         age:20
                      },{
                          name:'李四'
                      }
                  ]
              let arr1
      ={...arr}; arr1[1].name="張三" console.log(arr[1].name);// 張三 console.log(arr1[1].name);// 張三

  • concat

    • 利用陣列自帶的方法 Array.prototype.concat()

      let arr = [
                      {
                         age:20
                      },{
                          name:'李四'
                      }
                  ]
              let arr1
      ={...arr}; arr1[1].name="張三" console.log(arr[1].name);// 張三 console.log(arr1[1].name);// 張三

  • slice

    • 陣列的擷取方法

      let arr = [
                  1,3,
                      {
                         age:20
                      }
                  ]
              let arr1 = arr.slice() 
              arr1[2].age=30;
              console.log(arr[2].age); //30   
              console.log(arr1[2].age); //30 

注意:關於Array的slice和concat方法的補充說明:Array的slice和concat方法不修改原陣列,只會返回一個淺複製了原陣列中的元素的一個新陣列。

原陣列的元素會按照下述規則拷貝:

如果該元素是個物件引用(不是實際的物件),slice 會拷貝這個物件引用到新的數組裡。兩個物件引用都引用了同一個物件。如果被引用的物件發生改變,則新的和原來的陣列中的這個元素也會發生改變。 對於字串、數字及布林值來說(不是 String、Number 或者 Boolean 物件),slice 會拷貝這些值到新的數組裡。在別的數組裡修改這些字串或數字或是布林值,將不會影響另一個數組。

例如:

 
let arr = [
            1,3,
                {
                   age:20
                }
            ]
        let arr1 = arr.slice() 
        arr1[0]=2;
        console.log(arr[0]);//1
        console.log(arr1[0]);//2

2.深拷貝方法

  • JSON.parse(JSON.stringify())

    • 原理: 用JSON.stringify將物件轉成JSON字串,再用JSON.parse()把字串解析成物件,一去一來,新的物件產生了,而且物件會開闢新的棧,實現深拷貝。

      這種方法雖然可以實現陣列或物件深拷貝,但不能處理函式

         
       let arr = [
                      {
                         age:20
                      },{
                          name:'李四'
                      }
                  ]
              let arr1=JSON.parse(JSON.stringify(arr));
              arr1[1].name="張三"
              console.log(arr[1].name);// 李四
              console.log(arr1[1].name);// 張三



  • 手寫遞迴方法

    • 遞迴方法實現深度克隆原理:遍歷物件、陣列直到裡邊都是基本資料型別,然後再去複製,就是深度拷貝

      let arr = [
                  {name:'li'}, 
                  {age:12},
                  ()=>{return 4}
               ]
              let arr1 = deepClone(arr)//呼叫函式克隆
              console.log(arr1[2]);//()=>{return 4} 可以克隆函式
              console.log(arr === arr1);//false 因為深克隆引用地址不同
              arr1[0].name = "張三"
              console.log(arr[0].name);// li
              console.log(arr1[0].name);// 張三
      // 獲取物件的型別
              function getObjType(target) {
                  return Object.prototype.toString.call(target).slice(8, -1)
              }
              // 執行深克隆
              function deepClone(data) {
                  var type = getObjType(data);
                  var obj;
                  if (type === 'Array') {
                      obj = [];
                  } else if (type === 'Object') {
                      obj = {};
                  } else {
                      //不再具有下一層次
                      return data;
                  }
                  if (type === 'Array') {
                      for (var i = 0, len = data.length; i < len; i++) {
                          obj.push(deepClone(data[i]));
                      }
                  } else if (type === 'Object') {
                      for (var key in data) {
                          obj[key] = deepClone(data[key]);
                      }
                  }
                  return obj;
              };