Loading

对象的浅拷贝和深拷贝

对象的浅拷贝

浅拷贝的实现方式主要有以下几种:

  • Object.assign({}, obj)
  • 扩展运算符 {...obj}
  • for...in 遍历每个 key,一一赋值
  • for...of 遍历自身的可枚举属性

1.Object.assign

let obj = {
  name: 'Danny',
  age: 18
}

let o2 = Object.assign({}, obj)
console.log(o2)

2.扩展运算符

let o3 = {...obj}
console.log(o3)

3.for...in

let o4 = {}
for (let key in obj) {
  // 剥离原型链属性
  if (obj.hasOwnProperty(key)) {
    o4[key] = obj[key]
  }
}
console.log(o4)

4.for...of

let o5 = {}
// Object.keys() 返回自身的可枚举属性,不包括继承来的
for (let key of Object.keys(obj)) {
  o5[key] = obj[key]
}
console.log(o5)

对象的深拷贝

深拷贝的实现方式主要有以下几种:

  • JSON.parse(JSON.stringify(obj))
  • 循环 + 递归

1.JSON 实现

undefined 和 function 会丢失

let obj1 = {
  name: 'Danny',
  age: 18,
  campus: undefined,
  fn: ()=>{}
}
let o1 = JSON.parse(JSON.stringify(obj1))
console.log(o1) // { name: 'Danny', age: 18 }

2.循环 + 递归实现

结合网上的一些博客,实现了一个比较完美且易懂的深拷贝方案:可以拷贝对象、数组、函数、正则、日期类型,同时使用 WeakMap 解决了循环引用的问题

  • 循环引用
    使用 WeakMap 结构存储已经被拷贝IDE对象,每一个拷贝的时候就先向 WeakMap 查询该对象是否已经被拷贝,如果已经被拷贝则取出该对象并返回

  • 函数对象的拷贝

    使用 new Function 可以往函数中动态的传递内容,参考

// 判断是否为对象
function isObj(obj) {
  return (typeof obj === 'object' || typeof obj === 'function') 
    && obj !== null
}

function deepClone(obj, hash = new WeakMap()) {
  // 1.初始化 copy
  let copy
  let Constructor = obj.constructor
  switch (Constructor) {
    case RegExp:
      copy = new Constructor(obj)
      break
    case Date:
      copy = new Constructor(obj.getTime())
      break
    case Function:
      copy = new Constructor('return ' + obj.toString())()
      break
    default:
      // 对象、数组
      if (hash.has(obj)) return hash.get(obj)
      copy = new Constructor()
      hash.set(obj, copy)
  }
  // 2.遍历每个 key 赋值,遇到对象递归调用 deepClone 创建一个新的副本
  for (let key of Object.keys(obj)) {
    if (isObj(obj[key])) {
      copy[key] = deepClone(obj[key], hash)
    } else {
      copy[key] = obj[key]
    }
  }
  // 3.返回结果
  return copy
}

测试

const obj2 = {
  arr: [1, 2, 3],
  obj: { name: 'hehe'},
  fn: (x, y) => { console.log(x, y) },
  date: new Date(1996, 12),
  reg: /正则/ig,
  n: null,
  u: undefined
}
// 环引用,引用自身
obj2.a = obj2

let copy = deepClone(obj2)
console.log(copy)
// 测试函数拷贝
copy.fn(1, 2) // 可以传参
console.log(copy.fn === obj2.fn) // false

参考

posted @ 2021-11-17 15:48  neoscar  阅读(33)  评论(0编辑  收藏  举报