深拷贝的粗浅理解

114 阅读2分钟

一、深拷贝

在参数赋值的过程中,存在两种情况,一种是浅拷贝,一种是深拷贝。

其实理解起来也很简单,浅拷贝就是一个女生换了一身衣服,本质她还是她,内在没有改变。深拷贝,就是这个女生生了个孩子,这个孩子和她一样漂亮,然后这个女生不会因为她孩子的改变而改变。

比较官方的可以说用有没有创建新的内存空间来判断当前是否是深拷贝。如果是浅拷贝,就只是将指针指向同一片内存空间。深拷贝在创建对象的过程中还会创建新的内存空间。

二 、json序列化深拷贝

Json序列化是经常用到的,比如在axios封装的过程中,在序列化的过程中它也会过滤掉一些类型的参数。

const objStr = {
  a1: 1,
  a2: '2',
  a3: 0,
  a4: true,
  a5: false,
  a6: undefined,
  a7: null,
  a8: {},
  a9: () => {
    return this.a1
  },
  a10:NaN
}
console.log(JSON.stringify(objStr))
console.log(JSON.parse(JSON.stringify(objStr)))

image.png

在数据转换的过程中,它会自动的将undefined过滤掉,也会把NaN转换成null, functionsymbol也会被忽略掉。

但是在拷贝函数的情况下,是用JSON序列化来拷贝还是不错的选择,简单使用。

比如下

let obj1 = {a : 'obj1', b: 'obj2' }
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.a = 'obj2'
console.log(obj1,obj2)
obj1.a = 'a'
obj1.c = 'c'
console.log(obj1, obj2)

image.png

通过序列化参数,创建了新的内存空间,相互之间不受干扰。但是如果该参数存在function的情况下,该拷贝就不能使用了。

递归处理

这里需要考虑一个问题,是数据的类型,数据有两种类型,分别是ArrayObject,function是特殊的Object,那么这样就方便去处理数据了,如果是对象,那么就通过递归循环,非对象参数,就直接拷贝赋值,在函数里会独立创建一个返回参数,作为最后的返回值。

function deepClone(obj) {
  const result = obj.constructor === Array ? [] : {}
  for(let keys in obj) {
    if(obj.hasOwnProperty(keys)) {
      if (obj[keys] && typeof obj[keys] === 'object') {
        result[keys] = obj[keys].constructor === Array ? [] : {}
        result[keys] = deepClone(obj[keys])
      } else {
        result[keys] = obj[keys]
      }
    }
  }
  return result
}


这里做个测试结果

let obj1 = {
  a: 1,
  b: function() {
    return this.a
  }
}
let obj2 = deepClone(obj1)
obj2.a = 2
obj2.c = function() {
  console.log('this is c')
}
console.log(obj1)
console.log(obj2)
console.log(obj2.c())

image.png

从这里也看出了,通过递归深拷贝的对象是和原对象内存空间独立的,不存在相互依赖关系。