深拷贝,浅拷贝
1、会产生这种情况的原因:
首先,了解深浅拷贝,要先了解有两种数据类型,和两种内存的存储方式
数据类型分两种: 基本类型和引用类型
内存分为四个区域:栈区(堆栈),堆区,全局静态区,只读区(常量区和代码区)。
1.基本类型和引用类型
- 基本类型:就是值类型,即在变量所对应的内存区域存储的是值
- 引用类型: 就是地址类型,他保存的是一个地址
如图所示:
如果赋值
基本类型:
引用类型:
这里的 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验证