ECMAScript-淺拷貝和深拷貝

東東愛編碼發表於2020-10-23

一、ECMAScript-淺拷貝和深拷貝
1. 概念

深拷貝:拷貝的物件是新的物件,跟原來的物件不存在共享屬性。

淺拷貝:拷貝的物件只是引用原物件的屬性。

圖解:

我們現在有一個物件在記憶體中,

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Ig47tmeY-1603437827292)(../ECMAScript-imgs/image-20201023150232816.png)]

深拷貝:是兩個完全獨立的個體

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-KEzn3udO-1603437827295)(../ECMAScript-imgs/image-20201023150254593.png)]

淺拷貝:物件和函式部分只是引用

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-8aPFCL0l-1603437827298)(../ECMAScript-imgs/image-20201023150157541.png)]

2. Object.assign()存在的問題
// Object.assign()常常被用來拷貝物件,但是這種拷貝只是簡單的拷貝,不能進行深層次的拷貝,
// 原因:Object.assign()在進行復雜物件的拷貝的時候,只是把引用地址進行的替換,並沒有真正的拷貝值
// 簡單物件
let target = {
    d: 2,
    e: 3,
    f: 4
}

let source = {
 		g: 4
}
Object.assign(target, source)
console.log(target) // {d: 2, e: 3, f: 4, g: 4} 正常

// 複雜物件
let target = {
  a: {
    b: {
      c: 1
    },
    d: 2,
    e: 3,
    f: 4
  }
}

let source = {
  a: {
    b: {
      c: 1
    },
    d: 2,
    e: 3
  }
}
Object.assign(target, source)
console.log(JSON.stringify(target)) // {"a":{"b":{"c":1},"d":2,"e":3}} 丟失了f

// 拷貝出來的值,值改變兩者都不影響,叫深拷貝
let a = 5
let b = a
a = 6
console.log(a, b) // 6 5

// 拷貝出來的值,值改變影響到另一個值,叫淺拷貝
let obj1 = {
  name: 'zhangsan',
  age: 30
}
let obj2 = obj1
console.log(JSON.stringify(obj1)) // {"name":"zhangsan","age":30}
obj1.name = 'lisi' // 改變obj1的值
console.log(JSON.stringify(obj2)) // {"name":"lisi","age":30} obj2的值卻改變了
3. 其他拷貝也存在的問題
// 擴充套件符
const newObj = {...obj}
// Object.creact()
const newObj = Object.creact({},obj)
4. 怎麼去實現一個深拷貝
// 方式一:缺陷:如果物件中存在方法則轉化就會失敗
// 通過JSON.stringify()和JSON.parse()
let obj1 = {
  name: 'zhangsan',
  age: 30,
  study(){
    console.log(this.name)
  }
}
// 先通過JSON.stringify()將其轉換成json格式的字串
let str = JSON.stringify(obj1)
// 再轉換成json物件
let obj2 = JSON.parse(str)
// 更改obj1屬性的值
obj1.name = 'lisi'
console.log(obj2) // {name: "zhangsan", age: 30} 並未改變,但是方法丟失了

// 方式二:自己實現
let checkType = data => {
  return Object.prototype.toString.call(data).slice(8, -1)
}

console.log(checkType(function(){
  console.log('1111')
}))

let deepClone = target => {
  let targetType = checkType(target)
  let result
  if (targetType === 'Object') {
    result = {}
  } else if (targetType === 'Array') {
    result = []
  } else{
    return target
  }

  for(let key in target) {
    let value = target[key]
    let valueType = checkType(value)
    if(valueType === 'Object' || valueType === 'Array'){
      result[key] = deepClone(value)
    } else if (valueType === 'Function') {
      result[key] = target[key].bind(result)
    } else {
      result[key] = value
    }
  }
  return result
}

// 驗證一:
let arr1 = [1, 2, {age: 18}]
let arr2 = deepClone(arr1)
arr2[2].age = 40
console.log(arr1) // 互不影響
console.log(arr2)

// 驗證二:
let obj1 = {
  name: 'zhangsan',
  age: 30,
  study(){
    console.log(this.name)
  }
}
let obj2 = deepClone(obj1)

console.log(obj1) 
obj1.name = 'lisi'
console.log(obj1.study === obj2.study) // fasle

相關文章