JS中淺拷貝和深拷貝的使用,深拷貝實現方法總結

1、淺拷貝:兩個對象經過拷貝後雖然具有相同的屬性,但是他們都指向同一個內存空間。操作會引起引用,同一地址的變量一起改變。

let a = {x: 1}
let b = a
b.x = 2
console.log(b)   // {x: 2}
console.log(a)   // {x: 2}

2、深拷貝:兩個對象除了拷貝了一樣的屬性, 沒有任何其他關聯(指向不同的內存空間)。

實現深拷貝的方法:

(1)ES5 for循環賦值

//普通對象,單層屬性
let souceObj = {x: 1, y: 2} 
 
function clone(souceObj, targetObj = {}) {
    for (const key in souceObj) {
        targetObj[key] = souceObj[key]
    }
 
    return targetObj
}
 
let targetObj = clone(souceObj)
targetObj.x = 10
console.log(souceObj)   //{ x: 1, y: 2 }
console.log(targetObj)  //{ x: 10, y: 2 }

(2)JSON parse stringify

let souceObj = {x: 1, y: 2}
let targetObj = JSON.parse(JSON.stringify(souceObj))
targetObj.x = 10
console.log(souceObj)   //{ x: 1, y: 2 }
console.log(targetObj)  //{ x: 10, y: 2 

這樣做是真正的Deep Copy,這種方法簡單易用。

但是這種方法也有不少壞處,譬如它會拋棄對象的constructor。也就是深拷貝之後,不管這個對象原來的構造函數是什麼,在深拷貝之後都會變成Object。

這種方法能正確處理的對象只有 Number, String, Boolean, Array, 扁平對象,即那些能夠被 json 直接表示的數據結構。RegExp對象是無法通過這種方式深拷貝。

也就是說,只有可以轉成JSON格式的對象纔可以這樣用,像function沒辦法轉成JSON。

(3)ES6 操作符 ...

let souceObj = {x: 1, y: 2}
let targetObj = {...souceObj}
targetObj.x = 10
console.log(souceObj)   //{ x: 1, y: 2 }
console.log(targetObj)  //{ x: 10, y: 2 }

(4)ES6  Object.assign()

let souceObj = {x: 1, y: 2}
let targetObj = Object.assign({}, souceObj)
targetObj.x = 10
console.log(souceObj)   //{ x: 1, y: 2 }
console.log(targetObj)  //{ x: 10, y: 2 }

(5)遞歸深拷貝

function deepCopy(obj) {
  // 只拷貝對象
  if (typeof obj !== 'object') return;
  // 根據obj的類型判斷是新建一個數組還是一個對象
  var newObj = obj instanceof Array ? [] : {};
  for (let key in obj) {
    // 遍歷obj,並且判斷是obj的屬性才拷貝
    if (obj.hasOwnProperty(key)) {
      // 判斷屬性值的類型,如果是對象遞歸調用深拷貝
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
    }
  }
  return newObj;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章