<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺談深淺拷貝|手摸手帶你入坑

          共 11247字,需瀏覽 23分鐘

           ·

          2021-03-17 19:25

          前言

          再次談及深拷貝,已經(jīng)過了兩三年了!花有重開日人無再少年,從當(dāng)初的懵懵懂懂到現(xiàn)在的油膩大叔,害

          基本類型 與 引用類型

          在這里我們先說明 基本類型引用類型 的區(qū)別

          基本數(shù)據(jù)類型:直接存儲在棧 (stack) 中的數(shù)據(jù)

          String, Number, Boolean, Null, Undefined,Symbol

          let a = 1
          let b = a
          b = 2
          console.log(a,b)
          // 1 , 2

          ab 變量 都是基本類型,我們直接修改 b ,a 是不會被影響到的

          引用數(shù)據(jù)類型:存儲的是該對象在棧中引用,真實的數(shù)據(jù)存儲在堆(heap)

          Object 、Array 、Function 、Data

          題來?。?/p>

          let obj = {
            name'嚴家輝',
            age18
          }
          let obj1 = {
            name'嚴家輝',
            age18
          }
          console.log(obj === obj1)

          輸出什么?

          相信有一部分同學(xué)已經(jīng)知道了是 false,那是為什么呢,真相就是引用地址不同因為是引用類型

          引用類型的變量,== 和 === 只會判斷引用的地址是否相同,而不會判斷對象具體里屬性以及值是否相同

          如何比較一個對象是否相等?

          1.JSON.stringify

          console.log(JSON.stringify(obj) === JSON.stringify(obj1))
          // true

          我們現(xiàn)在是將obj 轉(zhuǎn)成了 string 類型,不會對比引用地址

          '{"name":"嚴家輝","age":18}' === ' {"age":18,"name":"嚴家輝"}'

          但是這樣有一個問題

          let obj = {
            name'嚴家輝',
            age18
          }
          let obj1 = {
            age18,
            name'嚴家輝'
          }
          console.log(JSON.stringify(obj) === JSON.stringify(obj1))

          obj1 的順序修改了一遍之后?現(xiàn)在這兩個對象是否相等?還是這樣轉(zhuǎn)為字符串,肯定返回false

          那么我們需要如何判斷兩個對象(不定順序的kv)是否相等呢?

          let obj = {
            name'嚴家輝',
            age18
          }
          let obj1 = {
            age18,
            name'嚴家輝'
          }
          const isSame = (obj1, obj2) => {
              var obj1keys = Object.keys(obj1);
              var obj2keys = Object.keys(obj2);
              if (obj2keys.length !== obj1keys.length)return false
              for (let i = 0; i <= obj1keys.length - 1; i++) {
                  let key = obj1keys[i]
                  if (!obj2keys.includes(key)) return false
                  if (obj2[key] !== obj1[key]) return false
              }
              return true
          }
          console.log(isSame(obj,obj1)) // true

          這樣對象值為基本數(shù)據(jù)類型的不管是順序是否一致都可以對比了

          關(guān)于引用地址

          好了,我們回過頭來看看這個

          let obj = {
            name'嚴家輝',
            age18
          }
          let obj1 = obj
          console.log(obj === obj1)

          我們在之前說過引用類型的 == 、=== 只是判斷它的引用地址是否相同

          那么它在這里的引用地址肯定是一樣的,故打印 true

          那么我現(xiàn)在需要修改 obj1age為 24

          let obj = {
            name'嚴家輝',
            age18
          }
          let obj1 = obj
          obj1.age = 24
          console.log('obj',obj)
          console.log('obj1',obj1)

          輸出什么呢?

          為啥obj也會改變呢

          當(dāng)我們使用=將這些變量賦值到另外的變量,實際上是將對應(yīng)的值拷貝了一份,然后賦值給新的變量。

          對象是通過引用傳遞,而不是值傳遞。也就是說,變量賦值只會將地址傳遞過去。

          故我們修改 obj1 其實也是修改的 obj 本身

          那么問題來了,假如我們在項目上面有個這樣的需求

          也就是我們目標(biāo)對象 data ,a 函數(shù)先執(zhí)行,然后執(zhí)行b函數(shù),但是b函數(shù)的要用到 data.name 為嚴家輝

          let data = {
              name'嚴家輝',
              age18
          }
          const a = () => data.name = '老嚴'
          const b = () => console.log('b函數(shù)',data.name) // 老嚴
          a()
          b()

          在這里我們就需要了解一下深拷貝了

          什么是深拷貝?

          在圖中我們可以看到我們在內(nèi)存中新開了一個堆用來拷貝obj的數(shù)據(jù),但是修改obj1不會影響obj

          建一個新的對象或數(shù)組,將原對象的各項屬性的“值”(數(shù)組的所有元素)拷貝過來,是“數(shù)據(jù)”而不是“引用地址” 我們希望在改變新的對象的時候,不影響原對象

          怎么實現(xiàn)呢?

          1、JSON 序列化

          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              }
          }
          const a = () => {
              // 核心內(nèi)容
              let data1 = JSON.parse(JSON.stringify(data))
              data1.name = '老嚴'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1.name)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          先通過 JSON.stringify 將對象轉(zhuǎn)為字符串再重新序列化為對象。

          這個應(yīng)該是最簡單的深拷貝了

          缺點是如果對象中包含函數(shù)會丟失

          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              },
             // + 個test函數(shù)
              testfunction({}
          }
          const a = () => {
              let data1 = JSON.parse(JSON.stringify(data))
              data1.name = '老嚴'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          看看 test 涼了沒

          2、for in 遍歷

          const deepCopy = obj => {
              // 判斷是數(shù)組還是對象
              let result = typeof obj.splice === "function" ? [] : {};
              if (obj && typeof obj === 'object') {
                  for (let key in obj) {
                      if (obj[key] && typeof obj[key] === 'object') {
                          //如果對象的屬性值為object的時候,遞歸調(diào)用deepClone,即在吧某個值對象復(fù)制一份到新的對象的對應(yīng)值中。
                          result[key] = deepCopy(obj[key]);
                      } else {
                          //如果對象的屬性值不為object的時候,直接復(fù)制參數(shù)對象的每一個鍵值到新的對象對應(yīng)的鍵值對中。
                          result[key] = obj[key];
                      }
                  }
                 // 返回拷貝完成后數(shù)據(jù)
                  return result;
              }
              return obj;
          }
          // 使用
          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              }
          }
          const a = () => {
              let data1 = deepCopy(data)
              data1.name = '隔壁小花'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          通過遍歷數(shù)據(jù)返回一個拷貝后船新的數(shù)據(jù)

          缺點:據(jù)說如果數(shù)據(jù)深度 > 1000+ 會爆棧

          3、lodash函數(shù)庫

          使用lodash函數(shù)庫來進行深拷貝

          html

          <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

          js

          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              }
          }
          const a = () => {
              // 核心代碼
              let data1 = _.cloneDeep(data)
              data1.name = '隔壁小花'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          4、$.extend

          html

          <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>

          js

          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              }
          }
          const a = () => {
              // 核心代碼
              let data1 = $.extend(true,{},data);
              data1.name = '隔壁老王'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          小結(jié)一下

          推薦使用第一種或者第二種,后面兩種需要通過引入外部庫才行

          其實還有其他的方法可以實現(xiàn)深拷貝,比如 Proxy 、樹遍歷等

          那淺拷貝又是什么?

          萬物皆有對立面,有深便有淺

          剛剛我們說深拷貝是將原對象的各項屬性的“值”(數(shù)組的所有元素)拷貝過來,不是引用地址,那么淺拷貝就是 拷貝原對象的引用地址

          對于淺拷貝而言,就是只拷貝對象的引用,而不深層次的拷貝對象的值,多個對象指向堆內(nèi)存中的同一對象,任何一個修改都會使得所有對象的值修改,因為它們公用一條數(shù)據(jù)

          找到前面的例子和圖,這就是一個最典型的淺拷貝

          let obj = {
            name'嚴家輝',
            age18
          }
          let obj1 = obj
          obj1.age = 24

          這下明白了嗎?

          啥,還不明白 ,那我們再寫倆栗子吧

          淺拷貝的實現(xiàn)

          1、for in

          const deepCopy = obj => {
              let result = typeof obj.splice === "function" ? [] : {};
              if (obj && typeof obj === 'object') {
                  for (let key in obj) {
                      // 我們直接去掉遞歸,讓第二層的數(shù)據(jù)直接賦值(引用地址)
                       result[key] = obj[key];
                  }
                  return result;
              }
              return obj;
          }
          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              }
          }
          const a = () => {
              let data1 = deepCopy(data);
              data1.name = '隔壁老王'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          我們直接使用深拷貝的第二個實現(xiàn)方式刪除遞歸,讓它直接賦值(引用地址),這就實現(xiàn)了一個淺拷貝

          2、Object.assign

          let data = {
              name'嚴家輝',
              age18,
              other: {
                  gender"男"
              }
          }
          const a = () => {
              // 核心代碼
              let data1 = Object.assign({},data);
              data1.name = '城中村村花'
              data1.other.gender = '女'
              console.log('a函數(shù)',data1)
          }
          const b = () => console.log('b函數(shù)',data) // 老嚴
          a()
          b()

          小結(jié)一下

          對于第一層的數(shù)據(jù)來說確實是拷貝成功了,但是在對象的屬性是引用類型數(shù)據(jù)時我們還是拷貝的引用地址

          總結(jié)

          深淺拷貝的區(qū)別就是前者將原數(shù)據(jù)重新復(fù)制了一份然后新開了一個地址,后者則是將原數(shù)據(jù)的引用地址拷貝了一份而已

          如有錯誤,望各位不吝賜教。

          參考文檔

          https://www.jianshu.com/p/f4329eb1bace

          https://segmentfault.com/a/1190000018592552?utm_source=sf-related


          瀏覽 61
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费特级黄毛片 | 黄色在线视频播放 | 爱爱无码免费视频 | 中文字幕欧美日韩VA免费视频 | 偷拍自拍视频网址 |