目录
一、问题引出
二、浅拷贝
1、通过解构重构实现浅拷贝
三、深拷贝
1、自定义实现深拷贝
2、JSON实现深拷贝
四、总结
一、问题引出
基础类型的数据存放:
let a = 100
let b = a
console.log("a:" + a, "b:" + b)
a = 50
console.log("a:" + a, "b:" + b)
打印:这里可以看到两个基础变量的值是互不影响的
这里a修改没有修改b的示意图如下:
基础类型的a和b都分别存放在栈内存里,当a被修改是b不会被影响。
下面我们将a和b换成对象类型:
let a = [1, 2, 3]
let b = a
console.log("a:" + a, "b:" + b)
a[0] = 100
console.log("a:" + a, "b:" + b)
打印:可以看到,当a被修改是b也发生了改变。
此时的内存分配示意图如下:
由于对象是存在堆内存里的,当a赋值给b时,其实仅是b指向了a的同一个堆地址,当a修改此地址的对象时,b指向的对象就是该对象,所以会同步改变。
解决方案有两个,浅拷贝和深拷贝。
二、浅拷贝
1、通过解构重构实现浅拷贝
let a = [1, 2, 3]
let b = [...a]
console.log("a:" + a, "b:" + b)
a[0] = 100
console.log("a:" + a, "b:" + b)
打印:此时,修改a并不会影响b的值。
此时的内存分配图如下:
通过以上方法,可以让b复制a的值重新生成一个新对象,在堆内存中重新开辟一个新的对象空间,此时,a和b的地址是不一样的。
你可能会说,这两个对象都完全独立开来了,怎么算浅拷贝呢,不应该是深拷贝吗?下面进一步实验:
let a = [1, 2, 3, [4, 5]]
let b = [...a]
console.log(a)
console.log(b)
a[3][0] = 10
console.log(a)
console.log(b)
打印:可以看到当我实验二维数组时,二维数组里的内容被修改,还是会连同b一起修改.
此时的内存发布图如下:
浅拷贝只会拷贝最近一层的数据,二维数组为更进一层的数据,第一层存的只是第二层数据的地址,浅拷贝不会拷贝第二层以上的数据,这就是出现上述现象的原因。
如果此时a改的是第一项,不会堆b有任何影响,当a改的是共同指向的地址里的数据时,b的那部分数据也会随之改动。
三、深拷贝
对于二中提到的情况对于的深拷贝示意图如下:
下面我们将通过代码来实现深拷贝:
1、自定义实现深拷贝
实现深拷贝的函数:
function deepClone(oldData) {
if (typeof oldData === "object" && oldData !== null) {
let res = Array.isArray(oldData) ? [] : {};
for (let k in oldData) {
if (oldData.hasOwnProperty(k)) {
res[k] = deepClone(oldData[k])
}
}
return res
} else {
return oldData
}
}
拷贝执行:
let obj = {
name: "Jack",
age: 18,
hobby: ["swimming", "jogging"],
fn() {
console.log(this.name)
}
}
let obj2 = deepClone(obj)
console.log(obj2)
obj.hobby[0] = "play"
obj.fn = function () {
console.log("obj:" + this.age)
}
console.log(obj)
console.log(obj2)
obj.fn()
obj2.fn()
打印:可以看到深拷贝成功了,函数也深拷贝成功了。
2、JSON实现深拷贝
网上有很多说可以实验JSON的序列化与反序列化实现深拷贝,但这样做其实是有缺点的,JSON的序列化与反序列化并不能拷贝函数类型。
let obj = {
name: "Jack",
age: 18,
hobby: ["swimming", "jogging"],
fn() {
console.log(this.name)
}
}
let obj3=JSON.parse(JSON.stringify(obj))
console.log(obj3)
打印:可以看到序列拷贝的并没有函数对象
四、总结
1、如果是基本数据类型,js都是采用深拷贝的,数据之间不会有任何影响;
2、可以通过解构重构或Object.assgin方法来实现浅拷贝;
3、深拷贝可以使用实验中的深拷贝递归函数来实现,对于一些没有函数的对象可以实验JSON.parse(JSON.stringify()) 的方法来快速实现深拷贝。
总结到此!