JS对象的深拷贝与浅拷贝写法总结

js中对于基本类型数据的拷贝(复制)就是值本身,而对于引用类型数据,则分为深拷贝和浅拷贝。

浅拷贝

js对象浅拷贝:拷贝的是其引用地址,也就是说,如果原地址中对象被改变了, 那么浅拷贝出来的对象也会相应改变

    let obj1 = {a:1};
    let obj2 = obj1;
    obj2.a = 2;
    console.log(obj1); //{a:2}
    console.log(obj2); //{a:2}
复制代码

深拷贝

引用类型数据的深拷贝在计算机中开辟了一块新的内存地址用于存放复制的对象,如果原地址中对象被改变了, 那么深拷贝出来的对象不会相应改变。

一、只能处理一层数据结构的深拷贝:

  • 1、数组:slice concat ...运算符
    • 注意:splice也能得到新数组,但splice操作会影响原数组
    let arr1 = [2,{name:"123"},3,4,5];
    let arr2 = arr1.slice();
    arr2[0] = 9;
    arr2[1].name = 999;
    console.log(arr1);//[ 2, { name: 999 }, 3, 4, 5 ]
    console.log(arr2);//[ 9, { name: 999 }, 3, 4, 5 ]
复制代码

上述例子中,分别改变数组第一项的值与第二项对象中name的值,打印出来的结果中arr1中的第一项未被修改,而第二项中的name被修改,说明slice只能拷贝单一层次结构的数据。

  • 2、对象{}:...运算符 Object.assign Object.create
    • 注意:Object.create(obj)的返回值是一个空对象,其__proto__指向了被拷贝的对象obj
    let obj1 = {name:"qiankaobei",other:{age:"123",height:"321"}};
    let obj2 = Object.assign({},obj1);
    obj2.name = 'yiceng';
    obj2.other.age = '999';
    console.log(obj1);//{ name: 'qiankaobei', other: { age: '999', height: '321' } }
    console.log(obj2);//{ name: 'yiceng', other: { age: '999', height: '321' } }
    复制代码
    单独说下Object.create()
    let obj11 = {name:"shenkaobei",other:{age:"123"}};
    let obj22 = Object.create(obj11);
    console.log(obj11);//{ name: 'shenkaobei', other: { age: '123' } }
    console.log(obj22);//{} 返回一个空对象
    console.log(obj22.name);//shenkaobei 能取到name值
    console.log(obj22.other.age);//123
    console.log(obj22.__proto__);//{ name: 'shenkaobei', other: { age: '123' } } obj22的__proto__指向了被拷贝对象
    复制代码

    至此我们知道,create返回一个空对象,并且这个空对象的__proto__指向了被拷贝对象,所以obj22能取到相应的属性值,接下来我们继续写:

    obj22.name = "888";
    obj22.other.age = "888";
    console.log(obj11);//{ name: 'shenkaobei', other: { age: '888' } } name没变 age被改变
    console.log(obj22);//{ name: '888' } 给obj22添加了name属性
    console.log(obj22.name);//888 取自obj22
    console.log(obj22.other.age);//888  取自原型
    //obj22.other与obj11.other指向同一个空间
    console.log(obj22.__proto__);//{ name: 'shenkaobei', other: { age: '888' } } 
    复制代码

    由此可见,实际上Object.object()采用的是继承原理,其第二个参数还可以设置属性描述符来达到进一步的应用,大家可以网搜一下

  • 3、当然也可以用 for for in for of 等系列循环

二、多层数据结构的深拷贝:

  • 1、JSON.parse(JSON.stringify(obj1))
    • 注意:会抛弃对象之前的constructor,拷贝之后指向Object,不能处理 Function、Date、RegExp等对象
    let arr_j = [function () {}, /\w/];
    let obj_j = {fn:function () {},reg:/\w/};
    let arr_p = JSON.parse(JSON.stringify(arr_j));
    let obj_p = JSON.parse(JSON.stringify(obj_j));
    console.log(arr_p);//[ null, {} ]
    console.log(obj_p);//{ reg: {} }
    复制代码

    由此可见,Function会被解析成null,RegExp被解析成{}

  • 2、递归拷贝: 创建一个新对象 + for in + 递归
    let obj_1 = {name:"shenkaobei",other:{age:"123",height:"321"}};
    function deepClone(obj) {
        if(obj == null)return;
        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 (const key in obj) {
            newObj[key] = deepClone(obj[key])
        }
        return newObj
    }
    let obj_2 = deepClone(obj_1);
    obj_2.other.age = "888";//改变第二层数据的值
    console.log(obj_1);//{ name: 'shenkaobei', other: { age: '123', height: '321' } }
    console.log(obj_2);//{ name: 'shenkaobei', other: { age: '888', height: '321' } }
    复制代码
  • 3、借助第三方库或插件
    • lodash: _.cloneDeep(obj1)
    • jq: $.extend(true, {}, obj1);

    具体用法大家可以网搜其API,在此就先不做过多阐述了

转载于:https://juejin.im/post/5b6c31abe51d4519247362ef

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值