1. 程式人生 > >淺拷貝與深拷貝的區別

淺拷貝與深拷貝的區別

1、資料型別:
    * 資料分為基本的資料型別(String, Number, boolean, Null, Undefined)和物件資料型別
    - 基本資料型別:
      特點: 儲存的是該物件的實際資料
    - 物件資料型別:
      特點: 儲存的是該物件在棧中引用,真實的資料存放在堆記憶體裡


2、複製資料
    - 基本資料型別存放的就是實際的資料,可直接複製
      let number2 = 2;
      let number1 = number2;

    - 物件資料存放的是物件在棧記憶體的引用,直接複製的是物件的引用
      let obj = {username: 'kobe'}
      let obj1 = obj; // obj1 複製了obj在棧記憶體的引用

 

3、為什麼要分深淺拷貝

淺拷貝:原始型別為值傳遞,物件型別仍為引用傳遞。

深拷貝(物件/陣列):所有元素或屬性均完全複製,與原物件完全脫離,也就是說所有對於新物件的修改都不會反映到原物件中。

     顯然,淺拷貝會帶來一個很大的問題。就是,如果我複製的值是一個引用地址,那麼我通過一個變數去修改這個物件,會導致所有該物件的引用都發生變化。

// Object.assign() 並不是深拷貝

object.assign(target,  source1, source2....)     將源物件的屬性複製到目標物件上

let obj1 = {

n: 12,

m: 'abc'

}

let obj2={}

object.assign(obj2, obj1)

console.log(obj2)

4、常用的拷貝技術
    1). arr.concat(): 陣列淺拷貝
    2). arr.slice(): 陣列淺拷貝
    3). JSON.parse(JSON.stringify(arr/obj)): 陣列或物件深拷貝, 但不能處理函式資料
    4). 淺拷貝包含函式資料的物件/陣列
    5). 深拷貝包含函式資料的物件/陣列


1.基本資料型別的淺拷貝

        let a = 'abc'
          let b = a
          b = '123'
          console.log(a)     abc
          console.log(b)          // 沒有對原來的資料影響
          
2.物件資料型別的淺拷貝
          let obj = {
        name: 'MsYangyang',
        age: 18,

        sex: {

            option1: '男'

            option2: '女'

           }
        }
       let obj2 = obj           // obj2儲存的是obj的地址值
       obj2.name = 'Li'          // 本質上修改了原物件的屬性值
       console.log(obj)   Li
       let obj3 = {}              /新建的物件

       object.assign(obj3, obj)

       obj3.name='xxxx'

       obj3.sex.option1='不男不女'

       console.log(obj)    Li    不男不女,女

       

3.函式的克隆
        let fun1 = function () {
        console.log('1111')
       }
        let fun2 = fun1
        fun2 = function () {
           console.log('2222')
        }
        fun1()     1111         // 沒有對原來的物件產生影響 :函式的克隆會在堆空間單獨開闢一片空間  與原來的物件互不影響
        fun2()     2222
          
深拷貝(本質:建立一個新的 {} 或 [] )
// 準備工作 :如何正確判斷判斷資料的型別?
  let obj3 = []
  console.log(Object.prototype.toString.call(obj3))

  // 建立一個用來判斷資料型別的函式
  function getObjClass(obj) {
    let result = Object.prototype.toString.call(obj).slice(8, -1)  //Array
    if (result === 'Undefined') {
      return 'Undefined'
    }else if (result === 'Null') {
      return 'Null'
    }else {
      return result
    }
  }

  // 建立一個深度遍歷物件/陣列的函式

  function deepClone(obj) {
    let objClass = getObjClass(obj)
    let result
    if(objClass === 'Object') {
      result = {}
    }else if (objClass === 'Array') {
      result = []
    }else {
      return obj       // 如果是其他資料型別就直接返回 不進行復制
    }

    // 遍歷目標物件
    for(let key in obj) {
      let value = obj[key]
      if (getObjClass(value) === 'Object') {
        result[key] = deepClone(value)
      }else if (getObjClass(value) === 'Array') {
        result[key] = deepClone(value)
      }else {
        result[key] = obj[key]
      }
    }
    return result
  }

  let obj4 = {
    name: 'haha',
    age: 20,
    sex: {
      option1: '男',
      option2: '女'
    }
  }

  let obj5 = deepClone(obj4)
  console.log(obj5, 'obj5')
  obj5.sex.option1 = '不男不女'
  console.log(obj4, 'obj4')