深拷贝和浅拷贝

121 阅读3分钟

深拷贝和浅拷贝

说明
基本数据类型不存在深浅拷贝,因为基本类型赋值时,赋的是数据(所以,不存在深拷贝和浅拷贝的问题)

什么是深拷贝和浅拷贝?

浅拷贝:基本数据类型,拷贝的是基本数据类型的值,引用类型只是对指针的拷贝,拷贝后两个指针指向同一个内存,同一份数据,意味着当原对象发生变化的时候,拷贝对象也跟着变化;
深拷贝:不但对指针进行拷贝,而且还对指针指向的内容进行拷贝,也就是另外申请了一块空间内存,内容和原对象一致,但是是两份独立的数据,更改原对象,拷贝对象不会发生变化。

深拷贝的作用

实际开发中也是非常有用的。例如后台返回了数据,我们需要对这些数据做操作,但是这些数据可能有其它地方也需要使用,直接修改就可能会造成很多隐性问题,而把数据做一次深拷贝就能让我们更安全安心的去操作这些数据,因为反正我们复制了一份下来。

深浅拷贝的几种方式

浅拷贝

//Object.assign()
//用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象
总结:原始对象的简单数据类型值没变,复杂数据类型值改变
const obj1 = { a: 1, b: 2, c: function () { d: 1 } }
const obj2 = {}
Object.assign(obj2, obj1)
obj2.a = 2
obj2.c.d = 2
console.log(obj1.a);   //1
console.log(obj1.c.d); //2

//解构赋值
总结:原始对象的简单数据类型值没变,复杂数据类型值改变
const obj1 = { a: 1, b: function () { c: 1 } }
const obj2 = { ...obj1 }
obj2.a = 2
obj2.b.c = 2
console.log(obj1.a);   //1
console.log(obj1.b.c); //2

//concat()、split()、slice()
总结:原始对象的简单数据类型值没变,复杂数据类型值改变
const arr1 = [1, { a: 1 }]
const arr2 = arr1.concat()
arr2[0] = 2
arr2[1].a = 2
console.log(arr1[0]);  //1
console.log(arr1[1].a);//2

深拷贝

//1. JSON.parse(JSON.stringify(obj))
//原理:JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,对象会开辟新的栈,实现深拷贝。
//局限性:不能拷贝方法
const arr = [1, { a: 1 }]
const arr1 = JSON.parse(JSON.stringify(arr))
arr1[1].a = 2
console.log(arr[1].a);//1

//2. 递归(推荐)
//对象、数组的深拷贝
//面试话术:
第一句:深拷贝是指新拷贝的对象不会影响就对象,要想实现深拷贝,可以用函数递归
第二句:普通拷贝的话采用赋值即可,但是遇见数组这样的我们再次调用递归即可
第三句:如果遇到对象形式,再次调用递归解决对象
第四句:一定先处理数组,在处理对象,因为万物皆对象,数组也是对象
function fn(old, newObj) {
  for (let k in old) {
    if (old[k] instanceof Array) {
      newObj[k] = []
      fn(old[k], newObj[k])
    } else if (old[k] instanceof Object) {
      newObj[k] = {}
      fn(old[k], newObj[k])
    } else {
      newObj[k] = old[k]
    }
  }
}
const a = { a: 1, b: { c: 1 } }
const b = {}
fn(a, b)
b.b.c = 2
console.log(a); //{ a: 1, b: { c: 1 } }

//3. loadash
//在线地址  https://cdn.bootcss.com/lodash.js/4.17.11/lodash.min.js