深浅拷贝

73 阅读2分钟

开发中经常需要复制一个对象。如果直接用赋值会有下面问题:

image.png

首先浅拷贝和深拷贝只针对引用类型

浅拷贝

浅拷贝:拷贝的是地址

常见方法:

  1. 拷贝对象:Object.assgin() / 展开运算符 {...obj} 拷贝对象

  2. 拷贝数组:Array.prototype.concat() 或者 [...arr]

// 展开运算符
const o = { ...obj }
o.age = 20
console.log(o)  // {uname: 'pink', age: 20}
console.log(obj) // {uname: 'pink', age: 18}

// Object.assign
const o = {}
Object.assign(o, obj)
o.age = 20
console.log(o)  // {uname: 'pink', age: 20}
console.log(obj) // {uname: 'pink', age: 18}

如果是简单数据类型拷贝值,引用数据类型拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)

image.png

深拷贝

深拷贝:拷贝的是对象,不是地址

常见方法:

  1. 通过递归实现深拷贝

  2. lodash/cloneDeep

  3. 通过JSON.stringify()实现

通过递归实现深拷贝

函数递归:

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数

简单理解:函数内部自己调用自己, 这个函数就是递归函数

递归函数的作用和循环效果类似

由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件 return

image.png

let i = 1
function fn() {
  console.log(`这是第${i}次`)
  if (i >= 6) {
    return
  }
  i++
  fn()
}
fn()

通过递归函数实现深拷贝(简版)

const obj = {
  uname: 'pink',
  age: 18,
  hobby: ['乒乓球', '足球'],
  family: {
    baby: '小pink'
  }
}
const o = {}

// 深拷贝(简版)
function deepCopy (newObj, oldObj) {
  for (const key in oldObj) {
    if (oldObj[key] instanceof Array) {
      newObj[key] = []
      deepCopy(newObj[key], oldObj[key])
    } else if (oldObj[key] instanceof Object) {
      newObj[key] = {}
      deepCopy(newObj[key], oldObj[key])
    } else {
      newObj[key] = oldObj[key]
    }

  }
}
deepCopy(o, obj)
console.log(o)
console.log(obj)

js库lodash里面cloneDeep内部实现了深拷贝

<script src="./lodash.min.js"></script>
<script>
const obj = {
  uname: 'pink',
  age: 18,
  hobby: ['乒乓球', '足球'],
  family: {
    baby: '小pink'
  }
}
const o = _.cloneDeep(obj)
console.log(o)
o.family.baby = '老pink'
console.log(obj)

通过JSON.stringify()实现

const obj = {
  uname: 'pink',
  age: 18,
  hobby: ['乒乓球', '足球'],
  family: {
    baby: '小pink'
  }
}
// 把对象转换为 JSON 字符串
// console.log(JSON.stringify(obj))
const o = JSON.parse(JSON.stringify(obj))
console.log(o)
o.family.baby = '123'
console.log(obj)