“可以手写一下深拷贝跟浅拷贝吗”
想必面试的时候大家都遇到过这道题吧,那么今天我们就来讲一下这个面试高频题:深/浅拷贝。
JavaScript 的 8 中数据类型
首先,需要先了解一下 JavaScript 的 数据类型,简单数据类型和复杂数据类型:
简单数据类型:Undefined、Null、Boolean、Number、 String、 Symbol(ES6 新增)、BigInt(ES10 新增)
复杂数据类型:Object
栈 与 堆 的概念
再来,了解一下内存的概念:JavaScript 的变量都存储在内存中,而内存为变量划分了两块区域,栈区域 和堆区域:
栈区域:容量小,速度快,就像是集装箱,先进后出,先放进去的货物最后再能取出来,简单数据类型都存储在栈区域中;
堆区域:容量大,速度慢,就像是仓库,要拿着取货码去找货物,而这个取货码在集装箱里;Object 顾名思义复杂在于它的由地址和内容两部分组成,地址存储在栈区域中,内容存储在堆区域中,要读取 Object 数据就要先拿着栈里的地址去堆中找内容;
深拷贝 和 浅拷贝的概念与区别:
-- | 拷贝区域 | 原数据均为简单数据类型 | 原数据包含对象 |
---|---|---|---|
浅拷贝 | 仅拷贝栈区域中的数据 | 改变不会使原数据一同改变[case1] | 改变会使原数据一同改变[case2] |
深拷贝 | 栈和堆区域中的数据一同拷贝 | 简单数据类型无深拷贝 | 改变不会使原数据一同改变[case3] |
这个区别其实很好理解,浅拷贝仅拷贝栈区域中的数据,所以当拷贝的内容包含对象时,就仅拷贝栈区域中存储对象地址的部分,没有拷贝堆区域中的内容部分,所以修改拷贝后的数据仍会使原数据一同改变;
而深拷贝会把堆中的数据也一同拷贝一份,并生成一个新的地址存储在栈中(就好比把仓库里的货物也克隆一个,并生成一个新的取货码与之对应);
接下来我们来逐个分析:
case1:浅拷贝-原数据均为简单数据类型
let a1 = [1, 2, 3];
let b1 = Array.from(a1); // 浅拷贝的方法之一
b1.push(4);
console.log(a1); // [1, 2, 3]
console.log(b1); // [1, 2, 3, 4]
case2:浅拷贝-原数据包含对象
let a2 = [1, 2, { a: 3 }];
let b2 = Array.from(a2);
b2.push(4);
b2[2].a = 5;
console.log(a2); // [1, 2, { a: 5}]
console.log(b2); // [1, 2, { a: 5}, 4]
case3:深拷贝-原数据包含对象
let a3 = [1, 2, { a: 3 }];
let b3 = JSON.parse( JSON.stringify(a3) ) // 实现深拷贝的一种
b3[2].a = 5;
console.log(a3); // [1, 2, { a: 3}]
console.log(b3); // [1, 2, { a: 5}]
以上,便是我对深拷贝与浅拷贝的理解,若有误欢迎大佬们纠错~