前言
javaScript的数据类型分为基本数据和引用数据类型,对于基本类型的拷贝,并没有深浅拷贝的区别,深浅拷贝只是针对引用数据类型。
一、如何区分深浅拷贝
- 把B复制A,A=B;
- 修改B时看A是否发生改变;
若A 发生改变 则是浅拷贝;
若A 不发生改变 则是深拷贝,深拷贝是拷贝对象各个层级的属性;
示例:
二、为什么会出现深浅拷贝
javescript把数据类型分为“基本数据类型”和“引用数据类型”,由于这两种数据类型的存储机制的原因,所以“引用数据类型“会存在深浅拷贝,而”基本数据类型“则不存在。
回顾:
基本数据类型:String、Number、Boolean、undefined、Null
引用数据类型:Object、Array、Function、RegExp、Date
分析:
-
基本数据类型的存储
var a = 1;
var a = 1; var b = a;
结论:
所以改变b的值并不会影响a的值。 -
引用数据类型的存储
var a = {
name:"zyk"
};
备注:
引用数据类型的变量名才存储在“栈内存”中,值存在“堆内存”,栈内存中存在指向堆内存的地址指针。
var a = {
name:"zyk"
};
var b = a;
b.name = "666zyk666";
结论:
a向b的赋值,其实是使b也有和a相同地址指针指向堆内存中的值。
所以修改b中name的值,同时会修改a中的值,这就是浅拷贝。
三、如何进行深拷贝
什么时候需要深拷贝?
赋值之后不需要改变原值的场景。
方法一:通过递归遍历进行深拷贝
var deepClone = function(obj){
//判断需要拷贝的数据是对象还是数组,依次觉得缓存数据的初始类型
var 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;
}
var a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
结果:
方法二:JSON对象的parse和stringify
var deepClone = function(obj){
//把对象转成字符串再转成对象,缓存到返回值中
var _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj);
return objClone
}
var a=[0,1,[2,3],4],
b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
结果:
备注:
不能深拷贝Function
方法三:structuredClone()
structuredClone() 是一个 JavaScript 的内置函数,用于深复制(deep clone)一个对象或值。
浏览器支持情况:
- Chrome 98
- Safari 137 (Technology Preview Release)
- Firefox 94
- Node.js 17.0
- Deno 1.14
限制:以下数据类型无法被深拷贝,使用structuredClone()方法时会报错
-
Functions
-
DOM 节点DOM nodes