JS 深浅拷贝的区别以及实现方式
在学习JS时最让我头疼的就是栈和堆以及一切概念性的问题 也是最近才把想给这个搞通提上了日程
简单来说 深浅拷贝的区别:
A复制了B 当改变 A 中的一个元素 B 中的这个元素也改变了 这就叫做浅拷贝
反之 改变 A 中的元素 B 中的元素并没有一起改变 这就叫做 深拷贝 深拷贝都是针对于较为复杂的object类型
这个也就要牵扯到栈和堆 以及 数据类型的概念了
JS几大基本数据类型: Null Undefined Number Boolean String Object Symbol(唯一值) BigInt(ES10未来 任意精度整数)
引用类型:Object类 --- 常规名值对的无序对象{a: 1} 数组:[1, 2] 函数等
1、基本类型 --- 名值都储存再栈内存中; let a = 1
当 b = a 复制时; 栈内存会新开辟一个内存
所以当你修改 a = 2 时 b 的值并不会发生改变 但这也算不上深拷贝 因为深拷贝都是针对于较为复杂的object类型
2、引用类型 名存栈内存中 值存堆内存中 但是栈内存会提供一个引用地址指向堆内存中的值
所以当 a = b 进行拷贝的时候 复制的是 a 的引用地址 而非堆里面的值
当我们 a [0] = 7 时 由于 a 和 b 指向的都是同一个堆内存值 所以 a 的修改 影响到了 b 这就是所谓的浅拷贝
所以要实现深拷贝 就是要在堆内存中新建一个 b 的堆内存
实现深拷贝
function deepClone(obj){
let a = JSON.stringify(obj);
b = JSON.parse(a)
return b
}
let a = [0, 1, [3,4], 9]
b = deepClone(a)
a[2][0] = 7
console.log(a, b) //[0,1,[7,4],9] [0, 1, [3,4], 9]
JSON.stringify() 和 JSON.parse() 的区别
JSON.stringify() 将对象转换为 JSON字符串 而 JSON.parse() 则是将JSON字符串转换为 对象
但是在使用JSON.parse()时 所转换的JSON字符串必须要符合JOSN格式 即键值都需要 "" 进行包裹
let a = '["1","2"]';
let b = "['1','2']";
console.log(JSON.parse(a));// Array [1,2]
console.log(JSON.parse(b));// 报错
递归方式实现:
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
数组放 splice concat slice 都不是真正的深拷贝 在一级层级是没问题的 当有二层层级时 就会被影响
let a=[1,2,3,4],
b=a.slice();
a[0]=2;
console.log(a,b);
let a=[0,1,[2,3],4], b=a.slice();
a[0]=1; a[2][0]=1; console.log(a,b);