深拷贝,浅拷贝

1、会产生这种情况的原因:

首先,了解深浅拷贝,要先了解有两种数据类型,和两种内存的存储方式

数据类型分两种: 基本类型和引用类型

内存分为四个区域:栈区(堆栈),堆区,全局静态区,只读区(常量区和代码区)。

1.基本类型和引用类型

  • 基本类型:就是值类型,即在变量所对应的内存区域存储的是值
  • 引用类型: 就是地址类型,他保存的是一个地址

如图所示:

锟斤拷是什么编码 java 为什么锟斤拷_赋值

如果赋值

基本类型:

锟斤拷是什么编码 java 为什么锟斤拷_赋值_02

引用类型:

锟斤拷是什么编码 java 为什么锟斤拷_赋值_03

这里的 arr2 = arr 就只是单纯的,将地址赋值过去,他内容的查找还是通过 地址定义到的 堆区

所以 引用类型的赋值会出现的这个问题,就是产生所谓的 浅拷贝

浅拷贝就会导致我们在进行 对象的赋值的时候,会直接改变最初的对象内容,让所有的赋值内容全都发生改变

2、解决方式

参见代码:

// 基本数据类型赋值后, 不会改变以前的变量
let str = 'ahhh'
let str2 = str
str2 = str2 + '111'
console.log(str, str2);

// 复杂类型 数组,函数,对象,会改变 ---- 浅拷贝
let a = {
  name: 'lmj',
  age: 19,
  arr: [1 ,2 ,3],
  de: undefined,
  handle: () => {
    console.log('handle');
  }
}
let b = a
b.name = 'wdf'
console.log(b, a);
// 1. 对象的浅拷贝,解决方法 使用 json 转换成字符串再转换成对象
// JSON 的转换方式,
let c = JSON.parse(JSON.stringify(a))
c.name = 'ttaa'
c.arr[0] = 4
console.log(a, c);
//  缺点: 数据类型为 function 和 undefined 情况下无有法赋值给C

// 2. Object.assign方法
let d = Object.assign({}, a)
d.name = 'xyy'
d.age = 30
d.arr[0] = 9
console.log(a, d);
// 缺点: 只能深拷贝 一级属性, 二级以上属性(引用类型)就是浅拷贝了

// 3, 使用扩展运算符  ES6 新语法
d = { ...a }
d.name = 'lyy'
d.age = 20
d.arr[0] = 7
console.log(a, d);
// 缺点: 与上面的 Object.assign 一样,只能深拷贝一级属性

// 4.  递归
function CloneDeep(data){
  const newData = Array.isArray(data) ? [] : {};
  for (let key in data){
    if (data.hasOwnProperty(key)) { // 这一行是添加了 hasOwnProperty验证
      if (data[key] && typeof data[key] === 'object') {
        newData[key] = CloneDeep(data[key])
      }else {
        newData[key] = data[key]
      }
      return newData
    }
  }
}

如此就需要注意:

  • 基本类型的变量的直接赋值就是深拷贝,改变内容不会影响原数据
  • 当赋值是一个对象的时候,可以实现深拷贝的一些方法,以及缺点
  • JSON:无法将对象内数据类型为 function 和 undefined 的赋值给新的对象
  • Object.assign:无法深拷贝对象内的二级属性
  • ES6的展开运算符:无法深拷贝对象内的二级属性
  • 递归:需要 hasOwnPropertyt验证