讲深拷贝的前言
数据类型
基 本 数 据 类 型 : n u m b e r , s t r i n g , b o o l e a n , n u l l , u n d e f i n e d , s y m b o l \color{skyblue}{基本数据类型:number, string, boolean, null, undefined, symbol} 基本数据类型:number,string,boolean,null,undefined,symbol
引 用 数 据 类 型 : o b j e c t , a r r a y , f u n c t i o n \color{skyblue}{引用数据类型:object, array, function} 引用数据类型:object,array,function
区别
基 本 类 型 没 有 属 性 和 方 法 , 保 存 在 栈 区 。 \color{skyblue}{基本类型没有属性和方法,保存在栈区。} 基本类型没有属性和方法,保存在栈区。
引 用 类 型 有 属 性 和 方 法 , 保 存 在 栈 区 和 堆 区 。 \color{skyblue}{引用类型有属性和方法,保存在栈区和堆区。} 引用类型有属性和方法,保存在栈区和堆区。
引 用 类 型 的 地 址 保 存 在 栈 区 , 数 据 保 存 在 堆 区 , 栈 区 的 地 址 指 向 堆 区 的 数 据 \color{red}{引用类型的地址保存在栈区,数据保存在堆区,栈区的地址指向堆区的数据} 引用类型的地址保存在栈区,数据保存在堆区,栈区的地址指向堆区的数据
什么是深拷贝、浅拷贝?
深拷贝:只有引用类型才涉及深拷贝,深拷贝指的是将引用类型的地址和数据全都拷贝到新的内存空间
浅拷贝:简单理解就是直接把引用类型赋值给一个新的变量,直接赋值的操作就是浅拷贝
深拷贝与浅拷贝的区别
浅拷贝只是拷贝了引用类型的地址,新拷贝的地址还是指向原来的数据,对新数据的修改会影响到原数据一起修改
深拷贝是拷贝了引用类型的地址和数据到新的内存空间,原地址指向原数据,新地址指向新数据,对新数据的修改不会影响原数据
为什么要深拷贝
先看浅拷贝会带来什么问题
let obj = {
a: 1,
b: 2
}
let newObj = obj
newObj.a = 3
console.log(obj.a, newObj == obj)//3 true
可 以 看 到 浅 拷 贝 在 修 改 新 对 象 n e w O b j 的 时 候 会 改 变 原 来 的 对 象 o b j \color{red}{可以看到浅拷贝在修改新对象newObj的时候会改变原来的对象obj} 可以看到浅拷贝在修改新对象newObj的时候会改变原来的对象obj
所 以 当 我 们 期 望 原 对 象 不 会 被 改 变 时 , 就 需 要 用 到 深 拷 贝 \color{red}{所以当我们期望原对象不会被改变时,就需要用到深拷贝} 所以当我们期望原对象不会被改变时,就需要用到深拷贝
深拷贝的常用方法
1、JSON.parse(JSON.stringify(obj)) 此 方 法 适 用 于 对 象 的 属 性 值 都 为 基 本 数 据 类 型 时 的 深 拷 贝 ( u n d e f i n e d 不 能 被 拷 贝 ) \color{red}{此方法适用于对象的属性值都为基本数据类型时的深拷贝(undefined不能被拷贝)} 此方法适用于对象的属性值都为基本数据类型时的深拷贝(undefined不能被拷贝)
let obj = {
a: 1,
b: 'str',
c: false,
d: null
}
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj, newObj == obj)//{a: 1, b: "str", c: false, d: null} false
2、递归深拷贝
function deepClone(sourceObj) {
if (!sourceObj || typeof sourceObj !== 'object' || Object.keys(sourceObj).length === undefined) {
return sourceObj
}
const cloneObj = sourceObj instanceof Array ? [] : {
}
Object.keys(sourceObj).forEach(obj => {
cloneObj[obj] = deepClone(sourceObj[obj])
})
return cloneObj
}
注 意 : 数 组 的 部 分 方 法 虽 然 能 返 回 一 个 新 的 数 组 , 但 他 本 质 上 还 是 浅 拷 贝 \color{red}{注意:数组的部分方法虽然能返回一个新的数组,但他本质上还是浅拷贝} 注意:数组的部分方法虽然能返回一个新的数组,但他本质上还是浅拷贝
例如Array.from()、slice()、concat()
let obj = [{
a: function () {
console.log(this)
},
b: {
id: 1
},
c: [1, 2, [3, [4, 5]]]
}]
let newObj = Array.from(obj)
newObj[0].c = 1
console.log(obj[0].c, newObj == obj)//1 false
可以发现,虽然新数组跟原数组不等,但是修改修改了新数组,原数组的值也会跟着变化