JS深拷贝与浅拷贝

一、如何简单区分深拷贝与浅拷贝

用语言描述,假设B复制了A,然后修改A,当修改A时,B发生了变化,说明这就是浅拷贝,若是B没有发生变化,就是深拷贝

二、JS基本数据类型与与引用数据类型数据存储

1、基本数据类型数据存储(number,string,boolean,null,undefined,symbol,BigInt)

基本类型的 名和值都存储在栈内存中
在这里插入图片描述
当你使用b= a 进行复制时,栈内存会开辟一个新的内存
在这里插入图片描述
所以当此时我们对a进行修改值的时候,b的值并不会发生改变,这就相当于深拷贝,但也并不算深拷贝,因为深拷贝是针对较为复杂的object类型数据

2、引入数据类型的数据存储

名 存在在栈内存中,值 存在于堆内存中,但是栈内存会提供一个引用的地址类型指向堆内存中的值
在这里插入图片描述
因此当我们使用b=a,进行拷贝的时候,复制的是a的引用地址,而并非堆里面的值
在这里插入图片描述
所以当我们使用a[0] = 1 的时候,由于a与b指向的是一个地址,所以b的值也会发生改变,这就是浅拷贝
在这里插入图片描述
思考:如果我们像基本数据类型一样,在堆内存中也开辟一个新的内存专门用来存放值,就可以达到深拷贝的效果

三、实现深拷贝的几种方法

1、使用递归去复制所有的层级属性

function deepClone(obj){
    //Array.isArray(obj)用于确定传递的值obj是否是一个数组
    let objClone = Array.isArray(obj)?[]:{};
    //typeof操作符用于返回一个字符串,表示未经计算的操作数的类型
    if(obj && typeof obj==="object"){
        //for ... in   用于对数组或者对象的属性进行循环操作
        for(key in obj){
            //hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。
            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);

let a = {ww:'12',qw:'33'}
    b=deepClone(a)
    a.ww = 'dd'
    console.log(a,b);

注意:slice()方法并不是深拷贝

这个看似像是深拷贝

let a=[1,2,3,4],
    b=a.slice();
a[0]=2;
console.log(a,b);

再试试这个,就会出现错误,深拷贝是会拷贝所有层的属性,而slice()仅仅是一层属性

let a=[0,1,[2,3],4]
//array.slice(start,end)  从已有的数组中返回选定的元素
b=a.slice();
a[0]=1;
//代表第3列第1行
a[2][0]=1;
console.log(a,b)

2、JSON对象的parse和stringify

function deepClone(obj){
    //JSON.stringify()把javaScript对象转换为字符串(序列化)
    //序列化的作用是存储(因为引用类型本身存储的仅仅只是一个地址,序列化后,会将引用类型换成字符串的类型然后可以在栈中保存值)

    //序列化注意事项:
    //      1、如果obj中有时间对象,则JSON.stringfy之后再JSON.parse的结果,时间将只是字符串的形式,而不是时间对象
    //      2、如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象;
    //      3、如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失;
    //      4、如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
    //      5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的,  则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor;
    //      6、如果对象中存在循环引用的情况也无法正确实现深拷贝;
    let _obj = JSON.stringify(obj)
    //JSON.parse()将数据转换为JS对象
    objClone = JSON.parse(_obj);
    return objClone
}    
let a=[0,1,[2,3],4],
    b=deepClone(a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值