数据类型
我们都知道我们的数据类型分为两大类:
- 基本的数据类型有:
number,string,boolean,null,undefined,symbol,
- 引用数据类型(Object)有:
{},[] 和函数
数据类型的存储方式
- 基本数据类型
基本类型–名值存储在栈内存中,例如let a=1;
当 b=a 进行赋值时,栈内存会开辟出一个新的内存存储 b
所以当你此时修改a=2,对b并不会造成影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的 object类型数据。 - 引用数据类型
引用数据类型–名
存在栈内存
中,值
存在于堆内存
中,但是栈内存会提供一个引用的地址指向堆内存中的值
例如:
let a=[0,1,2,3,4],
b=a;
console.log(a===b);
a[0]=1;
console.log(a,b);
当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
而当我们a[0]=1时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。
那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
浅拷贝深拷贝描述
浅克隆:直接将存储在栈
中的值赋值给对应变量,如果是基本数据类型
,则直接赋值对应的值
,如果是引用类型
,则赋值的是地址
基本数据类型
是直接存储在栈内存
中的,而引用数据类型
,则仅仅是把地址
存储在栈内存中,真正的数据是存储在堆内存
中的,赋值操作时,仅仅把地址
进行了赋值。
深克隆:就是把数据赋值给对应的变量,是拷贝对象各个层级
的属性,在内存中开辟一块新内存
,将原对象中的所有值
全部复制过去,与原对象完全脱离,修改新对象中的属性值不会影响
原对象、
浅克隆举例
let a = "xu";
let b = a;
alert( b ); // 'xu'
a = "ke";
alert( b ); // 'xu'
// 在这段代码中,把a赋值给b,当a的值发生变化时,并不影响b
let arr1 = [1, 2, 3];
let arr2 = arr1;
console.log( arr2 ); // [ 1, 2, 3]
arr1[0] = 2;
console.log( arr2 ); // [ 2, 2, 3]
// 在这段代码中,把arr1赋值给arr2,当arr1的值改变时,arr2对应的值也会改变
浅克隆实现方法:
- es6 拓展运算符
const obj ={
name:"xuke",
age:22
}
const obj2 = {...obj}
console.log(obj2.name) //xuke
- for循环遍历
let obj = {
name:"xuke",
age:22
}
function clone(obj ){
const result = {}
for(let key in obj){
result[key] = obj[key];
}
return result
}
let obj2 = clone(obj)
obj.name = "xiannv"
console.log(obj2.name) //xuke
console.log(obj2==obj) //false
obj2不会受obj的影响,因为被克隆的都是·
基本数据类型
,被存到栈
中的东西,
如果obj中存在引用数据类型的话:
let obj ={
name:"xuke",
age:22,
hobby:{
first:"eat",
second:"sleep"
}
}
function clone(obj ){
const result = {}
for(let key in obj){
result[key] = obj[key];
}
return result
}
let obj2 = clone(obj)
obj.hobby.first= "play"
console.log(obj2.hobby.first) //play
console.log(obj2==obj) //false
我们可以看到obj2复制的obj中含有
引用数据类型
,我们修改了obj中的引用数据类型
时,obj2中的也会改变
,数据在复制的时候是把obj中的引用数据类型
的地址
一起复制过去了,所以obj和obj2使用的是一个地址,所以obj2会受影响,我们想要不受影响就要使用深克隆
的方法。
深克隆实现方法:
JSON.parse(JSON.stringify())
实现深度克隆
let obj ={
name:"xuke",
age:22,
hobby:{
first:"eat",
second:"sleep"
}
}
let obj2 = JSON.parse(JSON.stringify(obj))
obj.hobby.first= "play"
console.log(obj2.hobby.first) //eat
console.log(obj2==obj) //false
JSON.parse(JSON.stringify())
实现深度克隆的弊端:
1.对象中的
方法
不能进行copy,会自动忽略
2.对象中的Date时间
不能进行copy, JSON.stringify方法会将日期自动转换为常规日期格式
3.
正则表达式
不能copy , JSON.stringify方法会将正则变为空对象
解决方法,用方法2将这些过滤掉:
2. 用递归
实现深克隆
let obj ={
name:"xuke",
age:22,
hobby:{
first:"eat",
second:"sleep"
}
}
function clone(obj ){
// 过滤特俗情况
if(obj===null) return obj
if(typeof obj !=='object') return obj
if(obj instanceof RegExp){
return new RegExp(obj)
}
if(obj instanceof Date){
return new Date(obj)
}
let newObj = new obj.constructor
for(let key in obj){
if (obj.hasOwnProperty(key)) {
newObj[key] = clone(obj[key] )
}
}
return newObj
}
let obj2 = clone(obj)
obj.hobby.first= "play"
console.log(obj2.hobby.first) //eat
console.log(obj2==obj) //false
使用:当copy源中没有引用类型,方法,正则,日期等值,只是普通的数据类型时,我们就可以用浅拷贝
的方法,反之用深拷贝