一目了然的深克隆,附带源码
JavaScript中的内存管理
在JS中,每一个数据都需要一个内存空间。内存空间又被分为两种。
栈内存(stock)
堆内存(heap)
堆栈空间分配区别:
- 栈:由操作系统自动分配释放存放函数的参数值,局部变量的值等。
简单数据类型存放到栈里面。 - 堆:存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。
复杂数据类型存放到堆里面。
注意:JavaScript中没有堆栈概念,通过栈堆的方式,可以让大家更容易理解代码的一些执行方式。
我画了一张图,可以帮助大家理解
那么问题来了,存在栈里面的简单数据类型有哪些,存在堆里面的复杂数据类型有哪里?
-
简单数据类型
又叫基本数据类型和值类型
string、number、null、undefined、Boolean、Symbol(ES6) -
复杂数据类型
又叫引用类型
object、array、function、date等等
了解了上面的知识以后,那我们来看看浅克隆和深克隆
首先我们先记住一句话,简单数据类型的传参,是值的直接传递,复杂数据类型的传参,是内存地址的传递。
浅拷贝
var obj = {
id:1,
name:'ysj',
msg:{
age:18
}
}
//把obj的属性和属性值拷贝到o对象中
var o ={}
for(var k in obj){
o[k] = obj[k]
}
我们输出o这个对象
到了这里obj对象就克隆给o这个对象了
还记得,我们之前的说的吗?复杂数据类型的传参,是内存地址的传递。
当我们去改变obj里面的msg里面的age时,o对象里面的msg里面的age也会被改变(反过来也是一样的)
为了解决这个问题,克隆之后,改变任一个对象里面的数据,另一个对象都不会发生改变
深拷贝
- JSON.parse方法
JSON对象parse方法可以将JSON字符串反序列化成JS对象,stringify方法可以将JS对象序列转化成JSON字符串,这两个方法结合起来就能产生一个便携的深克隆。
const newObj = JSON.parse(JSON.stringify(oldObj));
这个方法虽然可以解决绝大部分使用场景,但是却有很多的坑。
- 他无法实现对函数、RegExp等特殊对象的克隆。
- 会抛弃对象的constructor,所有的构造函数都会指向object
- 对象有循环引用,会报错
-
jQuery 中的 $.extend(true,target,object1[,objectN])
-
封装一个函数
function deepClone(newobj, oldobj) {
for (var k in oldobj) {
var item = oldobj[k];
if (item instanceof Array) {
newobj[k] = [];
deepClone(newobj[k], item)
} else if (item instanceof RegExp) {
newobj[k] = item;
} else if (item instanceof Function) {
newobj[k] = item;
} else if (item instanceof Date) {
newobj[k] = item;
} else if (item instanceof Object) {
newobj[k] = {};
deepClone(newobj[k], item)
} else {
newobj[k] = item;
}
}
}