js物件深複製

deeply發表於2021-09-09

1.使用slice或者concat進行陣列深複製

  • 對於值都是普通資料型別的陣列,可以使用陣列的slice或者concat函式來進行深複製。

let a = [1, 2, 3]let b = a.slice(0) //或者 let b = a.concat()b[0] = 0console.log(a[0] === 1) //true,改變b不影響a
  • 若陣列的項不是普通資料型別,而是引用資料型別,則使用slice或concat進行複製則只能進行一層深複製,也就是陣列項內部不能進行深複製。如下,陣列第一項為一個物件,改變b陣列第一項中物件的key屬性值,對應的a陣列也被改變了。

let a = [{  key: 1}]let b = a.slice(0) //或者 let b = a.concat()b[0].key = 0console.log(a[0].key === 0) //true,改變b影響a

2.使用JSON序列化函式進行深複製

function deepColne(obj) {  return JSON.parse(JSON.stringify(obj))
}

1.支援陣列和常規物件深複製

let obj = [{  key: 1}]let newObj = colne(obj)
newObj[0].key = 0console.log(obj[0].key) // 1

2.不支援undefined,會轉成null

let a = [1, , 2]let b = colne(a)console.log(a[1]) // undefinedconsole.log(b[1]) // null

3.不支援函式、RegExp、Date物件,會報錯

let func = function() {  console.log(1)
}let newFunc = colne(func)  //這直接報錯

3.使用遞迴進行物件深複製(遞迴為深度優先)

function deepColne(obj) {  let newObj  if(obj === null) {    return null
  } 
  else if (! (obj instanceof Object)) {    return obj
  } 
  else if (obj instanceof Date) {    return new Date(obj)
  }  else if (obj instanceof RegExp) {    return new RegExp(obj)
  }  else if (obj instanceof Function) {    //經測試複製函式有問題
    return eval(obj.toString())
  }  else if (obj instanceof Array) {
    newObj = []    for(item of obj) {
      newObj.push(clone(item))
    }
  }  else {
    newObj = Object.create(null)    for(let key of Object.keys(obj)) {
      newObj[key] = clone(obj[key])
    }
  }  return newObj
}

-缺陷:1)經測試函式複製有問題;2)不支援環的情況:物件的某個屬性值是物件本身,若出現環會迴圈遞迴,造成記憶體溢位。

4.使用寬度優先 + 佇列實現深複製,解決出現環的問題

-注意:不支援函式

function deepClone(obj) {  if(obj === null) {    return null
  } 
  /*obj是Date型別 */
  else if (obj instanceof Date) {    return new Date(obj)
  }  /*obj是正規表示式型別 */
  else if (obj instanceof RegExp) {    return new RegExp(obj)
  }  /*obj是陣列或者普通物件*/
  let newObj = (obj instanceof Array) ? [] : {},
    srcQueue = [obj],
    srcVisitedQueue = [],
    copyQueue = [newObj],
    copyVisitedQueue = [];  while (srcQueue.length > 0) {    let currentSrcElement = srcQueue.shift(),
      currentCopyElement = copyQueue.shift();

    srcVisitedQueue.push(currentSrcElement);
    copyVisitedQueue.push(currentCopyElement);    for (let key in currentSrcElement) {      /*基礎資料型別直接複製*/
      if (typeof currentSrcElement[key] !== 'object') {
        currentCopyElement[key] = currentSrcElement[key];
      } 
      /*日期物件*/
      else if (currentSrcElement[key] instanceof Date) {
        currentCopyElement[key] = new Date(currentSrcElement[key])
      }      /*正則*/
      else if (currentSrcElement[key] instanceof RegExp) {
        currentCopyElement[key] = new RegExp(currentSrcElement[key])
      }      /*物件資料型別或者陣列*/
      else {        // 有環的情況:判斷該物件是否已被訪問
        let index = srcVisitedQueue.indexOf(currentSrcElement[key]);        
        if (index >= 0) {
          currentCopyElement[key] = copyVisitedQueue[index];  //環(已訪問)直接複製
        } 
        else {          //非環物件或陣列加入到源佇列
          srcQueue.push(currentSrcElement[key]);  
          //copy物件對應位置暫時放置空物件或空陣列,下一輪迴圈賦值
          currentCopyElement[key] = currentSrcElement[key] instanceof Array ? [] : {};      
          copyQueue.push(currentCopyElement[key]); 
        }
      }
    }
  }  return newObj
}



作者:WHU_GIS_LJ
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1978/viewspace-2815223/,如需轉載,請註明出處,否則將追究法律責任。

相關文章