克隆
基础数据类型与栈内存
基础数据类型又叫做原始数据类型,有Number String Boolean Null Undefine Symbol(ES6新增)。
在计算机中声明这些数据是要占用内存的,存在即占用空间,这个空间就是栈内存。
打个比方,一本书有目录,然后目录记录具体的页码,这里的栈内存就相当于目录。
引用数据类型与堆内存
引用数据类型有Object Array Function
在计算机中声明这类数据也是要占用内存的,并且占用两种内存,堆内存和栈内存。
在栈内存中,存储着数据的指针,这个指针对应着堆内存的具体位置,而数据的具体位置就是存储在堆内存中。
打个比方,还是一本书,目录对应栈内存,具体每页则对应堆内存。
浅克隆
所以浅克隆的意思就是,同一本书,只克隆了目录,两个目录同时对应一本书,即多对一。
如果按照其中1个目录去修改书的内容,那么另一个目录所对应的内容也会随之改变,因为只有一本书。
实现浅克隆
function qianClone(old){
const newObj = {};
for(var key in old){
newObj[key] = old[key]
}
return newObj;
}
const oldObj = {
a: 1,
b: ['e', 'f', 'g'],
c: { h: { i: 2 } }
}
var newObj = qianClone(oldObj)
newObj.b[0] = 'aaaa'
console.log(newObj.b[0],oldObj.b[0]) //aaaa aaaa
console.log(oldObj.c.h === newObj.c.h); true
深克隆
那么深克隆就懂了吧,就是完全克隆一本书,目录和内容全部复制一份,变成两本一样,但又互不想干的书。
如果想对其中一本书的内容进行修改,也不会影响另一本书。
实现深克隆
有一种快速实现深克隆的方法,就是将一个对象转为字符窜,然后再将这个字符窜转为对象,这样就可以快速的实现深克隆了。
JSON.Stringify(obj) 可以将JS对象转为字符窜 JSON.parse(string) 可以将字符窜转为对象
var newObj = JSON.parse(JSON.Stringify(oldObj));
这种方法虽然快速,但有很多缺陷,比如:
1、无法对函数、正则等特殊对象进行克隆
2、会抛弃对象的constructor,所有的构造函数会指向Object
3、对象有循环引用,会报错
实现深度克隆2.0版本
const oldObj = {
a: 1,
b: ['e', 'f', 'g'],
c: { h: { i: 2 } }
};
function deepClone(origin,target){
var target = target || {},
toStr = Object.prototype.toString,
arrStr = "[object Array]";
for(var prop in origin){
if(origin.hasOwnProperty(prop)){
if(typeof(origin[prop]) == 'object'){
if(toStr.call(origin[prop]) == arrStr){
target[prop] = []
}else{
target[prop] = {}
}
deepClone(origin[prop],target[prop])
}else{
target[prop] = origin[prop]
}
}
}
return target;
}
var newObj = deepClone(oldObj);
这个深度克隆主要简单实现了数组和对象的克隆。
深度克隆实现是建立在浅克隆的基础之上的,主要思想如下。
1、for循环、判断是引用类型还是原始类型
2、原始类型就直接浅克隆,引用类型再继续判断是数组还是对象
3、对引用类型进行递归,直到数据为原始类型,此时跳出递归并且进行了浅克隆
4、至此,在浅克隆与递归算法的基础上实现了深克隆