深拷贝和浅拷贝探究详解

深拷贝和浅拷贝详解

一.概念

其实一般来说,我们遇到深浅拷贝的问题,都是针对引用数据类型的变量操作.先了解下数据类型

1.值类型和引用类型

值类型:直接存储其值,在内存中,是存在栈内存中

引用类型: 存储对值的引用,在内存中,是存在堆内存中,变量本身仅仅是一个指向堆中的实际数据地址,存在栈内存中(说白了,就是引用数据类型,实际上存在堆内存中,杂乱无序的放着,但是会有一个指针,指向堆内存中的地址, 而这个指针则是在栈内存中存储)

1.1值类型
  • Boolean
  • String
  • Undefined
  • Null (typeof 去判断时,会是object,因为null被转换成机器语言时很多个0,而只要前三个为0的话,就会被机器语言判断为object)
  • Number
  • Symbol(ES6 唯一性)
1.2 引用类型
  • Object
  • Array
  • Function
  • RegExp
  • Date
  • Function

在这里插入图片描述

1.浅拷贝

浅拷贝拷贝的是对象的指针,没有新建空间地址,新老对象共用的同一份地址,指向对内存中同一个地方,修改原来的对象会影响新对象

var obj1={
    a:1
}

var obj2=obj1;

obj2.a=5;
console.log('obj1.a',obj1.a); //5
console.log('obj2.a',obj2.a); //5

上述代码,就是一个浅拷贝,对象通过等于号直接赋值,是一个浅拷贝,obj1对象赋值给了obj2,实际上obj2只是拷贝了obj1在内存中栈中的一个地址,也就是指针,他们俩会共同指向堆中数据

2.深拷贝

深拷贝会在内存中,开辟一个相同的空间地址,并且复制相同的数值,两者互不干扰

2.1 JSON.parse+JSON.stringify

用JSON.stringify把对象转为字符串,再用JSON.parse把字符串转为新的对象.

      var obj3 = {
            classId: 2001,
            userinfo: {
                name: 'liuqiao',
                age: '27'
            }
        }

        var obj4 = JSON.parse(JSON.stringify(obj3));

        obj4.userinfo.name='zhangsan';
        console.log(obj3.userinfo.name); //liuqiao
        console.log(obj4.userinfo.name); //zhangsan

局限性:Number,String,Boolean,Array,可以转为JSON对象,但是function这种不行

2.2 lodash 实现深拷贝

lodash是一个高性能的 JavaScript 实用工具库,里面的lodash.cloneDeep()实现深拷贝,原理也是递归实现的

  <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
  <script>
          var obj3 = {
            classId: 2001,
            userinfo: {
                name: 'liuqiao',
                age: '27'
            }
          }

		var obj4 = _.cloneDeep(obj3);
        obj4.userinfo.name = 'zhangsan';
        console.log(obj3.userinfo.name); //liuqiao
        console.log(obj4.userinfo.name); //zhangsan
  </script>
2.3 递归拷贝

实现原理就是通过递归,循环遍历从最顶级开始,去找下一级,直到最后一层位置,然后赋值

  function deepClone(source) {
      		// 判断复制的目标是数组还是对象
            const targetObj = source.constructor === Array ? [] : {}; 
            for (let keys in source) { // 遍历目标
                if (source.hasOwnProperty(keys)) {
                    // 如果值是对象,就递归一下
                    if (source[keys] && typeof source[keys] === 'object') { 
                        targetObj[keys] = source[keys].constructor === Array ? [] : {};
                        targetObj[keys] = deepClone(source[keys]);
                    } else { 
                        // 如果不是,就直接赋值
                        targetObj[keys] = source[keys];
                    }
                }
            }
            return targetObj;
        }

        var obj3 = {
            classId: 2001,
            userinfo: {
                name: 'liuqiao',
                age: '27'
            }
        }
        
        var obj4 = deepClone(obj3);

        obj4.userinfo.name = 'zhangsan';
        console.log(obj3.userinfo.name); //liuqiao
        console.log(obj4.userinfo.name); //zhangsan
2.4 Object.assign()

实际上Object.assign是一个浅拷贝,但是如果是数据结构只有一层,可以实现深拷贝

		var obj6={};
        var obj5={
            a:1
        }

        obj6= Object.assign(obj6,obj3);
        obj6.a=2;
        console.log(obj6.a); //2
        console.log(obj5.a); //1

Object.assign,如果数据结构有多层,则是浅拷贝

    	var obj3 = {
            classId: 2001,
            userinfo: {
                name: 'liuqiao',
                age: '27'
            }
        }		

		var obj4={};

        obj4= Object.assign({},obj3);
        obj4.userinfo.name = 'zhangsan';
        console.log(obj3.userinfo.name); //zhangsan
        console.log(obj4.userinfo.name); //zhangsan
2.5 ES6扩展运算符 …

与Object.assign() 一样,如果数据结构只有一层,是深拷贝,多层结构了是浅拷贝,只能拷贝第一层的

扩展运算符浅拷贝

  		 var obj3 = {
            classId: 2001,
            userinfo: {
                name: 'liuqiao',
                age: '27'
            }
        }

        obj4 = { ...obj3 }
        obj4.userinfo.name = 'zhangsan';
        obj4.classId=3004;
        console.log(obj3.userinfo.name); //zhangsan
        console.log(obj4.userinfo.name); //zhangsan
        console.log(obj3.classId); //2001
        console.log(obj4.classId); //3004

扩展运算符深拷贝

	   var obj6 = {};
        var obj5 = {
            a: 1
        }

        obj6 = { ...obj5 };
        obj6.a = 2;
        console.log(obj6.a); //2
        console.log(obj5.a); //1

二.总结

实际项目中,根据不同的业务场景,判断是否需要使用深拷贝,方式有很多种,根据需求来自己实现即可!

猜你喜欢

转载自blog.csdn.net/liuqiao0327/article/details/106697045