js數組和對象相等判斷、拷貝詳解(結合幾個現象講解引用數據類型的趣事)

序言react

  最近遇到幾個js引用數據類型形成的bug,今天結合bug詳細分析一下,避免之後再犯,也但願能幫你們提個醒,強化js基本功。json

目錄數組

  一、淺拷貝、深拷貝,解決變量賦值相互影響問題 網絡

  二、判斷2個數組、對象是否相等函數

 

現象一測試

var a=1; var b=a; b=2; console.log(a) //1
console.log(b)      //2


var obj1 = {   id: 1,   info: { name: '張三'   } };
var obj2 = obj1; obj2.id = 2; obj2.info.name = '李四' console.log(obj1)   // {id:2, info:{name: '李四'}}
console.log(obj2)         // {id:2, info:{name: '李四'}}

  1. 現象分析: spa

    數組、對象都是用用數據類型。直接 = 賦值,或者 淺拷貝,這些變量實質上共享一個存儲空間的數據。當你修改其中一個對象變量時,
  另外一個也會變。 

2. 深淺拷貝
     淺拷貝: 簡單說,就是新的變量與原變量公用一個指針,即公用同一份存儲空間的數據。改變a,b也會變
   深拷貝: 簡單說就是把數據所有拔下來,從新存一下。a,b之間沒有任何牽連

   淺析:
  1. 這涉及到計算機原理的一些東西。js基本數據類型存在 棧內存 中, 當 a=b ,至關於新開闢一個存儲空間,因此互不影響。
  2. 引用數據類型,名 存在棧內存中,值存在堆內存中,棧內存會額外存一個指向堆內存的指針,其實就是 堆內存地址。
  3. 咱們對象 a=b 時,僅僅將名,即 棧內存中的數據複製了出來,可是棧內存的地址並無變,因此a,b值會保持一致,互相影響。


3. 幾個實現對象拷貝的方法
  let obj1 = { name: 11, age: 11, ope: { say: 1, get: 2 }}
  let obj2 = { }
  (1) let obj2 = { ...obj1 } let obj2 = { ...obj1 ,ope:22}
  這個拷貝不完全,他能夠深拷貝基礎數據類型,name 等修改不會影響,可是數組、對象不行,ope裏面的數據依舊相互影響,可是咱們
  能夠將這些引用數據類型給修改掉,這樣依舊能夠實現互不影響

  (2) let obj2 = Object.assign({ },obj1,...)
  原理是同樣的,也是隻對基本數據類型管用,這個靈活度,還不如上面那個

  (3) 經過 json 字符串、對象轉換的方式
  obj2 = JSON.stringify(obj1) 先轉 字符串
  obj2 = JSON.parse(obj2) 再轉對象

並且轉成字符串之後,還方便 網絡傳輸 、 存儲。
  


現象二
     var arr1 = [1,2,3]; var arr2 = [1,2,3]; var obj1 = {id:1,name:"張三"}; var obj1 = {id:'1',name:"張三"}; var arr3 = arr1; var obj3 = obj1; console.log(arr1 === arr2);//false
        console.log(obj1 === obj2);//false
        console.log(arr3 === arr1);//true
        console.log(obj3 === obj1);//true

  

  1. 現象分析:       指針

    由於 數組、對象是引用數據類型,變量存儲的是地址,真正是數據在地址指針指向的存儲單元,因此arr一、arr2的數據是放在不一樣存儲單元裏的。直接比較,地址確定是不一樣的。而賦值操做 arr3 = arr1 是將地址指針賦值,數組數據仍是隻放在一個存儲單元裏面,arr一、arr2 都存儲了這個地址,因此直接比較是相等的code

2. 如何實現 數組 對象的相等判斷
  方法一   轉換爲字符串再比較
  JSON.stringify(a1) == JSON.stringify(a2)
  或
  a1.toString() == a2.toString()

  問題:存在 1 和 '1' ,認爲是相同的狀況,只能根據本身狀況來了
  方法二
function equalJudgment(data1,data2) { var result = true
              if (data1 && data2 && data1.constructor === Array && data2.constructor === Array) { if (data1.length !== data2.length) { result = false } else { for (var i=0;i<data1.length;i++) { if (data1[i].constructor === Array && data2[i].constructor === Array){ if (!equalJudgment(data1[i], data2[i])) { result = false
                        return result } } else if (data1[i].constructor === Object && data2[i].constructor === Object){ if (!equalJudgment(data1[i], data2[i])) { result = false
                        return result } } else { if (data1[i] !== data2[i]){ result = false
                        return result } } } } } else if (data1 && data2 && data1.constructor === Object && data2.constructor === Object) { var key1 = Object.getOwnPropertyNames(data1) var key2 = Object.getOwnPropertyNames(data2) if (key1.length !== key2.length) { result = false } else { for (var i=0;i<key1.length;i++) { if (key2.indexOf(key1[i]) === -1) { result = false
                      return result } else if (data1[key1[i]].constructor === Array && data2[key1[i]].constructor === Array) { if (!equalJudgment(data1[key1[i]], data2[key2[i]])) { result = false
                        return result } } else if (data1[key1[i]].constructor === Object && data2[key1[i]].constructor === Object) { if (!equalJudgment(data1[key1[i]], data2[key1[i]])) { result = false
                        return result } }else { if (data1[key1[i]] !== data2[key1[i]]){ result = false
                        return result } } } } } else { result = 'Input error!' } return result }

  

  以上 js 函數是我本身寫的,通過測試沒有問題 ,網上有不少實現的方法,可是大多都是沒法解析多層數組、對象嵌套的狀況 (說實話沒啥卵用),可是我的以爲這個方法寫的有些囉嗦,拋磚引玉,有更好的方法但願你們不吝分享。   ps:順便幫我測測bug,雖然各類狀況都試過,應該是沒問題對象

總結

  上述的2個現象在碼代碼過程當中應該會常常遇到,特別是處理像  react、Vue 生命週期函數的時候、state使用修改的時候,常常會遇到引用數據類型帶來的問題,不經意間就出問題了,但願這些能幫到你們,如有錯誤,望指出!!!

相關文章
相關標籤/搜索