浅拷贝与深拷贝的区别

1、数据类型:
    * 数据分为基本的数据类型(String, Number, boolean, Null, Undefined)和对象数据类型
    - 基本数据类型:
      特点: 存储的是该对象的实际数据
    - 对象数据类型:
      特点: 存储的是该对象在栈中引用,真实的数据存放在堆内存里
 

3、为什么要分深浅拷贝

浅拷贝:原始类型为值传递,对象类型仍为引用传递

深拷贝(对象/数组):所有元素或属性均完全复制,与原对象完全脱离,也就是说所有对于新对象的修改都不会反映到原对象中

     显然,浅拷贝会带来一个很大的问题。就是,如果我复制的值是一个引用地址,那么我通过一个变量去修改这个对象,会导致所有该对象的引用都发生变化。

// Object.assign() 并不是深拷贝

object.assign(target,  source1, source2....)     将源对象的属性复制到目标对象上

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

//$.extend()浅拷贝

        var obj1={'a':1};
        var obj2={'b':{'b1':22,'b2':33}};

        $.extend(obj1, obj2);   //obj1拷贝了obj2的属性

        console.log(obj1)  // {'a':1,'b'{'b1':22,'b2':33}}
        console.log(obj1.b.b1)  // 22
        obj2.b.b1 = 44
        console.log(obj1.b.b1)   //44  obj1.b仅拷贝了obj2的引用,所以受原obj2的影响

//$.extend()深拷贝

        var obj1={'a':1};
        var obj2={'b':{'b1':22,'b2':33}};

        $.extend(true,obj1, obj2);   //第一个参数设为true表示深复制

        console.log(obj1)  // {'a':1,'b'{'b1':22,'b2':33}}
        console.log(obj1.b.b1)  // 22

        obj2.b.b1=44;   //obj2重新赋值
        console.log(obj1.b.b1)  // 22 obj1拷贝了obj2的所有属性以及值,并不受obj2的影响

4、常用的拷贝技术

由于数组内部属性值为引用对象,因此使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址。

因此,slice和concat这两个方法,仅适用于对不包含引用对象的一维数组的深拷贝

    1). arr.concat(): 数组浅拷贝
    2). arr.slice(): 数组浅拷贝
    3). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 但不能处理函数数据
    4). 浅拷贝包含函数数据的对象/数组
    5). 深拷贝包含函数数据的对象/数组

        // concat深拷贝
        var arr1 = [1,2,3];
        var arr2 = [4,5,6];
        var result = arr1.concat(arr2);
        console.log(result);                //[1, 2, 3, 4, 5, 6]
        console.log(arr1, arr2);            // [1, 2, 3]  [4, 5, 6]

        //slice深拷贝
        var arr1 = ["1","2","3"];
        var arr2 = arr1.slice(0);
        arr2[1] = "9";
        console.log("数组的原始值:" + arr1 );        //1,2,3
        console.log("数组的新值:" + arr2 );          //1,9,3

        //concat浅拷贝
        var arr1 = [{"name":"weifeng"},{"name":"boy"}];//原数组
        var arr2 = [].concat(arr1);//拷贝数组
        arr1[1].name="girl";
        console.log(arr1);// [{"name":"weifeng"},{"name":"girl"}]
        console.log(arr2);//[{"name":"weifeng"},{"name":"girl"}]

        //slice浅拷贝
        var a1=[["1","2","3"],"2","3"],a2;
        a2=a1.slice(0);
        a1[0][0]=0; //改变a1第一个元素中的第一个元素
        console.log(a2[0][0]);  //影响到了a2       //0

        // 由于数组内部属性值为引用对象,因此使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址。
        // 因此,slice和concat这两个方法,仅适用于对不包含引用对象的一维数组的深拷贝

1.基本数据类型的浅拷贝   

let a = 'abc'
let b = a
b = '123'
console.log(a)     //abc
console.log(b)     // 123  没有对原来的数据影响

2.对象数据类型的浅拷贝

    let obj = {
                name: 'MsYangyang',
                age: 18,
                sex: {
                    option1: '男',
                    option2: '女'
                   }
                }
        //        let obj2 = obj             // obj2保存的是obj的地址值
        //        obj2.name = 'Li'          // 本质上修改了原对象的属性值
        //        console.log(obj)         //Li

               let obj3 = {}            //新建的对象
               Object.assign(obj3, obj)

               obj3.name='yyn'

               obj3.sex.option1='不男不女'

               console.log(obj3)         
               console.log(obj);

       

3.函数的克隆

 let fun1 = function () {
        console.log('1111')
       }
        let fun2 = fun1
        fun2 = function () {
           console.log('2222')
        }
        fun1()     1111         // 没有对原来的对象产生影响 :函数的克隆会在堆空间单独开辟一片空间  与原来的对象互不影响
        fun2()     2222

深拷贝(本质:创建一个新的 {} 或 []

    1. for in 实现深拷贝(递归)
          // 准备工作 :如何正确判断数据的类型?
          let obj3 = []
          console.log(Object.prototype.toString.call(obj3))   //[object Array]

          // 创建一个用来判断数据类型的函数
          function getObjClass(obj) {
            let result = Object.prototype.toString.call(obj).slice(8, -1)  //Array
            if (result === 'Undefined') {
              return 'Undefined'
            }else if (result === 'Null') {
              return 'Null'
            }else {
              return result
            }
          }

          // 创建一个深度遍历对象/数组的函数(递归)
          function deepClone(obj) {
            let objClass = getObjClass(obj)
            let result
            if(objClass === 'Object') {
              result = {}
            }else if (objClass === 'Array') {
              result = []
            }else {
              return obj       // 如果是其他数据类型就直接返回 不进行复制
            }
            // 遍历目标对象
            for(let key in obj) {
              let value = obj[key]
              if (getObjClass(value) === 'Object') {
                result[key] = deepClone(value)
              }else if (getObjClass(value) === 'Array') {
                result[key] = deepClone(value)
              }else {
                result[key] = obj[key]
              }
            }
            return result
          }

          let obj4 = {
            name: 'haha',
            age: 20,
            sex: {
              option1: '男',
              option2: '女'
            }
          }

          let obj5 = deepClone(obj4)
          console.log(obj5, 'obj5')
          obj5.sex.option1 = '不男不女'
          obj5.name = 'yyn'
          console.log(obj4, 'obj4')

2. JSON方法实现

    //_tmp和result是相互独立的,没有任何联系,有各自的存储空间。
        let deepClone = function (obj) {
            let _tmp = JSON.stringify(obj);//将对象转换为json字符串形式
            let result = JSON.parse(_tmp);//将转换而来的字符串转换为原生js对象
            return result;
        };

        let obj1 = {
            weiqiujaun: {
                age: 20,
                class: 1502
            },
            liuxiaotian: {
                age: 21,
                class: 1501
            }
        };

        let test = deepClone(obj1);
        console.log(test);

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值