1. 程式人生 > 程式設計 >帶你搞懂js的深拷貝

帶你搞懂js的深拷貝

目錄
  • 深拷貝
    • 資料儲存方式
    • 什麼是淺/深拷貝
    • 常用深拷貝實現
      • 1.通過JSON.stringify和JSON.parse
      • 2.擴充套件運算子
      • 3.手寫遞迴深拷貝函式
  • 總結

    js深拷貝

    在講正題之前我們要先了解資料儲存的方式

    資料儲存方式

    在講之前我們要先知道值型別和引用型別的儲存方式。

    在資料型別中有兩種資料型別。

    值型別:字串(String)、數字 (Number)、布林 (Boolean)、空(Null)、未定義(Undefined)、Symbol

    存放在棧記憶體中的簡單資料段,資料大小確定,記憶體空間大小可以分配。

    引用資料型別:物件 (Object)、陣列 (Array)、函式 (Function)。

    存放在堆記憶體中的物件,在棧記憶體中存的是一個指YFtvO

    針,這個指標指向堆記憶體一個位置。再從堆記憶體中取得所需的資料。

    儲存如下圖:

    在這裡插入圖片描述

    什麼是淺/深拷貝

    講完儲存的方式,我們來講講淺拷貝和深拷貝

    拷貝也就是我們常常講的copy,ctrl+c,ctrl+v,那麼我們來看看例子

    當我們對分別值型別和引用型別進行賦值。

         var a = 5
         var b = a
         b += 5
         console.log('a=' + a,'b=' + b)
         var arr=[1,2,3]
         var brr=arr
         brr.push(10)
         console.log("arr為",arr)
         console.log("brr為",brr)
    

    在這裡插入圖片描述

    現象:我們發現值型別並沒有互相受到影響,然而陣列(引用型別)brr陣列新增元素的時候改變了arr陣列。

    解釋分析:淺拷貝只會發生在引用型別身上,對於引用型別如果之進行簡單的賦值,只會賦值指向堆記憶體的指標,這種稱為淺拷貝。而深拷貝就是完全拷貝一個引用型別,為不是地址指標。

    淺拷貝看下面這張原理圖:

    在這裡插入圖片描述

    常用深拷貝實現

    那麼我們在賦值引用型別的時候肯定不能出現淺拷貝的現象,對原資料產生影響了。那麼就要進行深拷貝

    1.通過JSON.stringify和JSON.parse

    可以深拷貝的陣列和物件,但是不能拷貝函式,可以進行物件或者陣列的巢狀拷貝。

    缺點:無法實現對物件中方法的深拷貝

    使用

         var brr=JSON.parse(JSON.stringify(arr))
    

    例子:

      var arr = {
             name: '浪漫主義碼農',age: 20,adress: ['jiangxi','changsha'],friends: {
                 friend1: '張三',friend2: '李四'
             },function(){
                 console.log("我是浪漫主義的物件")
             }
         }
         var brr=JSON.parse(JSON.stringify(arr))
         brr.name='法外狂徒張三'
         brr.adress[0]='長沙'
         console.log("arr為",brr)
    

    在這裡插入圖片描述

    2.擴充套件運算子

    利用了物件的結構賦值特性方法。

    缺點:無對物件裡面巢狀的物件進行深拷貝,相當於只是對一層引用物件進行深拷貝

    使用:

         var brr={...arr}
    

    例子:

      var arr = {
             name: '浪漫主義碼農',客棧         function(){
                 console.log("我是浪漫主義的物件")
             }
         }
         var brr={...arr}
         brr.name='法外狂徒張三'
         brr.adress[0]='長沙'
         console.log("arr為",brr)
    

    在這裡插入圖片描述

    3.手寫遞迴深拷貝函式

    完美解決

    函式:

      //使用遞迴實現深拷貝
         function deepClone(obj) {
             //判斷拷貝的obj是物件還是陣列
             var objClone = Array.isArray(obj) ? [] : {};
             if (obj && typeof obj === "object") { //obj不能為空,並且是物件或者是陣列 因為null也是object
                 for (key in obj) {
                     if (obj.hasOwnProperty(key)) {
                         if (obj[key] && typeof obj[key] === "object") { //obj裡面屬性值不為空並且還是物件,進行深度拷貝
                             objClone[key] = deepClone(obj[key]); //遞迴進行深度的拷貝
                         } else {
                             objClone[key] = obj[key]; //直接拷貝
                         }
                     }
                 }
             }
             return objClone;
         }
    

    例子:

          var arr = {
             name: '浪漫主義碼農',fun: function(){
                 console.log("我是" + this.name + "的物件")
             }
         }
         var brr = deepClone(arr)
         brr.name = '法外狂徒張三'
         brr.adress[0] = '長沙'
         console.log("arr為",arr)
         arr.fun()
         console.log("brr為",brr)
         brr.fun()
     ​
         //使用遞迴實現深拷貝
         function deepClone(obj) {
             //判斷拷貝的obj是物件還是陣列
             var objClone = Array.isArray(obj) ? [] : {};
             if (obj && typeof obj === "object") { //obj不能為空,並且是物件或者是陣列 因為null也是object
                 for (key in obj) {
                     if (obj.hasOwnProperty(key)) {
                         if (obj[key] && typeof obj[key] === "object") { //obj裡面屬性值不為空並且還是物件,進行深度拷貝
                             objClone[key] = deepClone(obj[key]); //遞迴進行深度的拷貝
                         } else {
                             objClone[key] = obj[key]; //直接拷貝
                         }
                     }
                 }
             }
             return objClone;
         }
    

    在這裡插入圖片描述

    總結

    本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注我們的更多內容!