1.为什么有深拷贝
在js中数据被分为了基础类型和引用类型;
基础类型:String、Boolean、Number,Undefined、Null;
引用类型:对象、数组、函数;
基本类型和引用类型由于两者在内存中存储的方式不同,造成两者访问的方式也不同。其中,基本类型存储在内存的栈中,是按值访问;引用类型存储在内存的堆中,是按引用访问
例:
let num1 = 10;
let num2 = 20;
let arr1 = [1,2,3,4,5];
let arr2 = arr1;
由于arr1与arr2指向的是同一个内存,所以不管是修改了arr1还是arr2,内存里面的数据都会发生变化,导致所有指向该内存的变量均变化。
在内存中的存储如图:
实现深拷贝的方法:
1.使用递归的方式实现数组、对象的深拷贝
function deepClone(obj){
// 判断要进行深拷贝的是数组还是对象
var objClone = Array.isArray(obj)?[]:{};
// 进行深拷贝的数值不能为空,并且是对象或者是数组
if(obj && typeof obj === 'object'){
for(let key in obj){
// 判断自身是否有这个属性
if(obj.hasOwnProperty(key)){
// 判断属性是否为引用类型
if(obj[key]&& typeof obj[key] === 'object'){
objClone[key] = deepClone(obj[key]);
}else{
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
2.使用JSON.parse(JSON.stringify())
其过程利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象;
注意事项:
- 如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
- JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
- 如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
代码示例
let oldArr = [1,2,3,4,5];
let oldObj = {
name:"demo",
age:'12',
sex:'男',
firend:{
name:"test",
age:'14'
},
hobby:function(){
console.log("hobby")
},
data: new RegExp('\\w+'),
isNaN:NaN
}
let newArr = deepClone(oldArr);
newArr[3] = 33;
console.log(newArr,'newArr',oldArr,'oldArr')
let newOjb = deepClone(oldObj);
newOjb.sex = '女';
console.log(newOjb,'newOjb',oldObj,'oldObj')
let jsonOjb = JSON.parse(JSON.stringify(oldObj));
jsonOjb.firend.age = '0';
console.log(jsonOjb,'jsonOjb',oldObj,'oldObj')