浅谈深浅拷贝

 一、JS的数据类型

要想学习深浅拷贝,首先需要了解javascript的数据类型

javascript 中有两种数据类型,分别是基本数据类型(Number、String、Undefined、Boolean、Null、Symbol)和引用数据类型(对象、数组、函数)。

基本数据类型是按值访问的,操作的就是变量保存的;如果是引用类型,则是通过保存在变量中的引用类型的地址来操作实际对象。

基本类型是不可变的,任何方法都无法改变一个基本类型的值,也不可以给基本类型添加属性或者方法。但是可以为引用类型添加属性和方法,也可以删除其属性和方法。

下面请看示例:

let num1 = 10;
let obj1 = {
    name: "ding"
}

let num2 = num1;
let obj2 = obj1;

num2 = 20;
obj2.name = "bai";

console.log(num1); // 10
console.log(obj1.name); // bai

可以看出赋值的时候,基本类型是在栈内存中重新开辟内存,存放变量num2,所以在栈内存中存放的基本数据类型是不会相互影响的。引用类型复制的只是引用地址,指向的是堆内存中同一地址的同一对象,修改时会相互影响。

所以对于基本类型的拷贝,并没有深浅拷贝的区别,我们所说的深浅拷贝都是对于引用类型而言的。

二、浅拷贝

浅拷贝的意思就是只复制引用,而未复制真正的值,源对象和目标对象共享同一块内存,一个修改时另一个也跟着修改。上述代码就是利用 = 赋值操作实现的浅拷贝。也可以利用Object.assign或展开运算符 ... 来实现浅拷贝。

通过 Object.assign 实现,Object.assign第一级属性深拷贝,以后级别属性浅拷贝。

let a = {
  age: 1,
  name: { asd: "123" }
};
let b = Object.assign({}, a);
b.age = 2;
b.name.asd = "456";
console.log(a.age, a.name.asd); //1 ‘456’

 通过展开运算符 ... 来实现深拷贝,但是需要注意的是只针对对象的第一级属性有效

var arr = {
  name: "aaa",
  other: {
    name: "bbb"
  }
};
var arr2 = { ...arr };
arr2.name = "AAA";
arr2.other.name = "BBB";
console.log(arr);   // { name: 'aaa', other: { name: 'BBB' } }
console.log(arr2);  // { name: 'AAA', other: { name: 'BBB' } }

三、深拷贝

深拷贝实现的是真正意义上的对象的拷贝。深拷贝会创造一个一模一样的对象,其内容地址是自助分配的,拷贝结束之后,内存中的值完全相同,但是内存地址是不一样的,目标对象跟源对象不共享内存,修改任何一方的值,不会对另外一方造成影响。

可以通过JSON.parse(JSON.stringify(object))实现深拷贝:

var arr = {
  name: "aaa",
  other: {
    name: "bbb"
  }
};
var arr2 = JSON.parse(JSON.stringify(arr));
arr2.name = "AAA";
arr2.other.name = "BBB";
console.log(arr);   // { name: 'aaa', other: { name: 'bbb' } }
console.log(arr2);  // { name: 'AAA', other: { name: 'BBB' } }

实现原理:拷贝一个字符串会开辟一个新的存储地址,这样就切断了引用对象的指针联系,所以先转成一个字符串,在解析出对象,这样就可以深拷贝一个对象 。

补充:

JSON.parse(str) 用于从一个字符串中解析出 json 对象,JSON.stringify(obj)用于从一个对象解析出字符串。

自己实现一个深拷贝函数:

function deepClone(obj) {
    let res;
    if (typeof obj === 'object') {
        if (obj === null) {
            res = obj;
        } else {
            res = Array.isArray(obj) ? [] : {};
            for (let key in obj) {
                let val = obj[key];
                res[key] = deepClone(val);
            }
        }
    } else {    
      // 除了数组和对象之外的类型
      res = obj;
    }
    return res;  
}

验证:

let obj = {
    a: {
        name: '小明'
    },
    b: 111,
    c: [1,2,3,4],
    d: '你好',
    e: null,
    f: function() {}
};
let b = deepClone(obj);
obj.a.name = 222;
console.log(obj,b);

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值