JS 數組、對象的深拷貝


博客地址:https://ainyi.com/72

JavaScript 程序中,對於簡單的數字、字符串可以通過 = 賦值拷貝
但是對於數組、對象、對象數組的拷貝,就有淺拷貝和深拷貝之分

淺拷貝就是當改變了拷貝后的數據,原數據也會相應改變

來說說深拷貝

數組深拷貝

遍歷賦值

不推薦此方法

let a = [1, 2, 3]
let b = []
for (let val of a) {
  b.push(val)
}
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

slice()

數組方法 slice() 可從已有的數組中返回選定的元素
那么設置為 0,就是返回整個數組

let a = [1, 2, 3]
let b = a.slice(0)
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

concat()

數組方法 concat() 連接一個或多個數組,並返回一個副本
那么不設置參數,就返回本數組

let a = [1, 2, 3]
let b = a.concat()
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

ES6 方法

let a = [1, 2, 3]
let b = [...a]
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
let a = [1, 2, 3]
let b = Array.from(a)
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

對象深拷貝

Object.assign()

Object.assign(target, obj)

let a = { name: 'krry' }
let b = Object.assign({}, a)
b.name = 'lily'
a // { name: 'krry' }
b // { name: 'lily' }

注意使用 assign() 有如下特點:

  1. 不會拷貝對象繼承的屬性、不可枚舉的屬性、屬性的數據屬性/訪問器屬性
  2. 可以拷貝 Symbol 類型

擴展運算符

let a = { name: 'krry' }
let b = { ...a }
b.name = 'lily'
a // { name: 'krry' }
b // { name: 'lily' }


以上是簡單數組、對象的深拷貝方法,但是對於二維數組、對象數組、對象里包含對象,以上方法均達不到深拷貝方法
以上只能達到數組、對象的第一層的深拷貝,對於里面的數組或對象屬性則是淺拷貝,因為里面的內存地址只是拷貝了一份,但都是指向同一個地址
所以當改變數組、對象里的數組元素或對象,原數據依然會改變

二維數組、對象數組、多層對象的深拷貝

最常用的 JSON 序列化與反序列化

使用 JSON.parse(JSON.stringify(obj))

let a = [1, [2, {aa: 2}, [4]], {aa: 5, cc: { dd: 6 }}]
let b = JSON.parse(JSON.stringify(a)) // 完美

通過 JSON.stringify 實現深拷貝有幾點要注意
  1. 拷貝的對象的值中如果有函數、undefined、symbol,則經過 JSON.stringify() 序列化后的 JSON 字符串中這個鍵值對會消失
  2. 無法拷貝不可枚舉的屬性,無法拷貝對象的原型鏈
  3. 拷貝 Date 引用類型會變成字符串
  4. 拷貝 RegExp 引用類型會變成空對象
  5. 對象中含有 NaN、Infinity 和 -Infinity,則序列化的結果會變成 null
  6. 無法拷貝對象的循環應用(即 obj[key] = obj)

自己實現深拷貝方法

function deepCopy(obj) {
  let result = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object') {
        result[key] = deepCopy(obj[key]);   // 遞歸復制
      } else {
        result[key] = obj[key];
      }
    }
  }
  return result;
}

lodash 的深拷貝 cloneDeep

使用 lodash 插件的深拷貝方法

// 官方例子
var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

傳送門:https://www.lodashjs.com/docs/4.17.5.html#cloneDeep

博客地址:https://ainyi.com/72


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM